1/* 2 * Copyright (C) 2014 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 17package com.android.server.telecom; 18 19import android.os.Handler; 20import android.os.Message; 21import android.telecom.PhoneAccountHandle; 22 23import com.android.internal.os.SomeArgs; 24import com.android.internal.telecom.IInCallAdapter; 25 26/** 27 * Receives call commands and updates from in-call app and passes them through to CallsManager. 28 * {@link InCallController} creates an instance of this class and passes it to the in-call app after 29 * binding to it. This adapter can receive commands and updates until the in-call app is unbound. 30 */ 31class InCallAdapter extends IInCallAdapter.Stub { 32 private static final int MSG_ANSWER_CALL = 0; 33 private static final int MSG_REJECT_CALL = 1; 34 private static final int MSG_PLAY_DTMF_TONE = 2; 35 private static final int MSG_STOP_DTMF_TONE = 3; 36 private static final int MSG_POST_DIAL_CONTINUE = 4; 37 private static final int MSG_DISCONNECT_CALL = 5; 38 private static final int MSG_HOLD_CALL = 6; 39 private static final int MSG_UNHOLD_CALL = 7; 40 private static final int MSG_MUTE = 8; 41 private static final int MSG_SET_AUDIO_ROUTE = 9; 42 private static final int MSG_CONFERENCE = 10; 43 private static final int MSG_SPLIT_FROM_CONFERENCE = 11; 44 private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 12; 45 private static final int MSG_PHONE_ACCOUNT_SELECTED = 13; 46 private static final int MSG_TURN_ON_PROXIMITY_SENSOR = 14; 47 private static final int MSG_TURN_OFF_PROXIMITY_SENSOR = 15; 48 private static final int MSG_MERGE_CONFERENCE = 16; 49 private static final int MSG_SWAP_CONFERENCE = 17; 50 51 private final class InCallAdapterHandler extends Handler { 52 @Override 53 public void handleMessage(Message msg) { 54 Call call; 55 switch (msg.what) { 56 case MSG_ANSWER_CALL: { 57 SomeArgs args = (SomeArgs) msg.obj; 58 try { 59 call = mCallIdMapper.getCall(args.arg1); 60 int videoState = (int) args.arg2; 61 if (call != null) { 62 mCallsManager.answerCall(call, videoState); 63 } else { 64 Log.w(this, "answerCall, unknown call id: %s", msg.obj); 65 } 66 } finally { 67 args.recycle(); 68 } 69 break; 70 } 71 case MSG_REJECT_CALL: { 72 SomeArgs args = (SomeArgs) msg.obj; 73 try { 74 call = mCallIdMapper.getCall(args.arg1); 75 boolean rejectWithMessage = args.argi1 == 1; 76 String textMessage = (String) args.arg2; 77 if (call != null) { 78 mCallsManager.rejectCall(call, rejectWithMessage, textMessage); 79 } else { 80 Log.w(this, "setRingback, unknown call id: %s", args.arg1); 81 } 82 } finally { 83 args.recycle(); 84 } 85 break; 86 } 87 case MSG_PLAY_DTMF_TONE: 88 call = mCallIdMapper.getCall(msg.obj); 89 if (call != null) { 90 mCallsManager.playDtmfTone(call, (char) msg.arg1); 91 } else { 92 Log.w(this, "playDtmfTone, unknown call id: %s", msg.obj); 93 } 94 break; 95 case MSG_STOP_DTMF_TONE: 96 call = mCallIdMapper.getCall(msg.obj); 97 if (call != null) { 98 mCallsManager.stopDtmfTone(call); 99 } else { 100 Log.w(this, "stopDtmfTone, unknown call id: %s", msg.obj); 101 } 102 break; 103 case MSG_POST_DIAL_CONTINUE: 104 call = mCallIdMapper.getCall(msg.obj); 105 if (call != null) { 106 mCallsManager.postDialContinue(call, msg.arg1 == 1); 107 } else { 108 Log.w(this, "postDialContinue, unknown call id: %s", msg.obj); 109 } 110 break; 111 case MSG_DISCONNECT_CALL: 112 call = mCallIdMapper.getCall(msg.obj); 113 if (call != null) { 114 mCallsManager.disconnectCall(call); 115 } else { 116 Log.w(this, "disconnectCall, unknown call id: %s", msg.obj); 117 } 118 break; 119 case MSG_HOLD_CALL: 120 call = mCallIdMapper.getCall(msg.obj); 121 if (call != null) { 122 mCallsManager.holdCall(call); 123 } else { 124 Log.w(this, "holdCall, unknown call id: %s", msg.obj); 125 } 126 break; 127 case MSG_UNHOLD_CALL: 128 call = mCallIdMapper.getCall(msg.obj); 129 if (call != null) { 130 mCallsManager.unholdCall(call); 131 } else { 132 Log.w(this, "unholdCall, unknown call id: %s", msg.obj); 133 } 134 break; 135 case MSG_PHONE_ACCOUNT_SELECTED: { 136 SomeArgs args = (SomeArgs) msg.obj; 137 try { 138 call = mCallIdMapper.getCall(args.arg1); 139 if (call != null) { 140 mCallsManager.phoneAccountSelected(call, 141 (PhoneAccountHandle) args.arg2, args.argi1 == 1); 142 } else { 143 Log.w(this, "phoneAccountSelected, unknown call id: %s", args.arg1); 144 } 145 } finally { 146 args.recycle(); 147 } 148 break; 149 } 150 case MSG_MUTE: 151 mCallsManager.mute(msg.arg1 == 1); 152 break; 153 case MSG_SET_AUDIO_ROUTE: 154 mCallsManager.setAudioRoute(msg.arg1); 155 break; 156 case MSG_CONFERENCE: { 157 SomeArgs args = (SomeArgs) msg.obj; 158 try { 159 call = mCallIdMapper.getCall(args.arg1); 160 Call otherCall = mCallIdMapper.getCall(args.arg2); 161 if (call != null && otherCall != null) { 162 mCallsManager.conference(call, otherCall); 163 } else { 164 Log.w(this, "conference, unknown call id: %s", msg.obj); 165 } 166 } finally { 167 args.recycle(); 168 } 169 break; 170 } 171 case MSG_SPLIT_FROM_CONFERENCE: 172 call = mCallIdMapper.getCall(msg.obj); 173 if (call != null) { 174 call.splitFromConference(); 175 } else { 176 Log.w(this, "splitFromConference, unknown call id: %s", msg.obj); 177 } 178 break; 179 case MSG_TURN_ON_PROXIMITY_SENSOR: 180 mCallsManager.turnOnProximitySensor(); 181 break; 182 case MSG_TURN_OFF_PROXIMITY_SENSOR: 183 mCallsManager.turnOffProximitySensor((boolean) msg.obj); 184 break; 185 case MSG_MERGE_CONFERENCE: 186 call = mCallIdMapper.getCall(msg.obj); 187 if (call != null) { 188 call.mergeConference(); 189 } else { 190 Log.w(this, "mergeConference, unknown call id: %s", msg.obj); 191 } 192 break; 193 case MSG_SWAP_CONFERENCE: 194 call = mCallIdMapper.getCall(msg.obj); 195 if (call != null) { 196 call.swapConference(); 197 } else { 198 Log.w(this, "swapConference, unknown call id: %s", msg.obj); 199 } 200 break; 201 } 202 } 203 } 204 205 private final CallsManager mCallsManager; 206 private final Handler mHandler = new InCallAdapterHandler(); 207 private final CallIdMapper mCallIdMapper; 208 209 /** Persists the specified parameters. */ 210 public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper) { 211 ThreadUtil.checkOnMainThread(); 212 mCallsManager = callsManager; 213 mCallIdMapper = callIdMapper; 214 } 215 216 @Override 217 public void answerCall(String callId, int videoState) { 218 Log.d(this, "answerCall(%s,%d)", callId, videoState); 219 if (mCallIdMapper.isValidCallId(callId)) { 220 SomeArgs args = SomeArgs.obtain(); 221 args.arg1 = callId; 222 args.arg2 = videoState; 223 mHandler.obtainMessage(MSG_ANSWER_CALL, args).sendToTarget(); 224 } 225 } 226 227 @Override 228 public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) { 229 Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage); 230 if (mCallIdMapper.isValidCallId(callId)) { 231 SomeArgs args = SomeArgs.obtain(); 232 args.arg1 = callId; 233 args.argi1 = rejectWithMessage ? 1 : 0; 234 args.arg2 = textMessage; 235 mHandler.obtainMessage(MSG_REJECT_CALL, args).sendToTarget(); 236 } 237 } 238 239 @Override 240 public void playDtmfTone(String callId, char digit) { 241 Log.d(this, "playDtmfTone(%s,%c)", callId, digit); 242 if (mCallIdMapper.isValidCallId(callId)) { 243 mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, (int) digit, 0, callId).sendToTarget(); 244 } 245 } 246 247 @Override 248 public void stopDtmfTone(String callId) { 249 Log.d(this, "stopDtmfTone(%s)", callId); 250 if (mCallIdMapper.isValidCallId(callId)) { 251 mHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget(); 252 } 253 } 254 255 @Override 256 public void postDialContinue(String callId, boolean proceed) { 257 Log.d(this, "postDialContinue(%s)", callId); 258 if (mCallIdMapper.isValidCallId(callId)) { 259 mHandler.obtainMessage(MSG_POST_DIAL_CONTINUE, proceed ? 1 : 0, 0, callId).sendToTarget(); 260 } 261 } 262 263 @Override 264 public void disconnectCall(String callId) { 265 Log.v(this, "disconnectCall: %s", callId); 266 if (mCallIdMapper.isValidCallId(callId)) { 267 mHandler.obtainMessage(MSG_DISCONNECT_CALL, callId).sendToTarget(); 268 } 269 } 270 271 @Override 272 public void holdCall(String callId) { 273 if (mCallIdMapper.isValidCallId(callId)) { 274 mHandler.obtainMessage(MSG_HOLD_CALL, callId).sendToTarget(); 275 } 276 } 277 278 @Override 279 public void unholdCall(String callId) { 280 if (mCallIdMapper.isValidCallId(callId)) { 281 mHandler.obtainMessage(MSG_UNHOLD_CALL, callId).sendToTarget(); 282 } 283 } 284 285 @Override 286 public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, 287 boolean setDefault) { 288 if (mCallIdMapper.isValidCallId(callId)) { 289 SomeArgs args = SomeArgs.obtain(); 290 args.arg1 = callId; 291 args.arg2 = accountHandle; 292 args.argi1 = setDefault? 1 : 0; 293 mHandler.obtainMessage(MSG_PHONE_ACCOUNT_SELECTED, args).sendToTarget(); 294 } 295 } 296 297 @Override 298 public void mute(boolean shouldMute) { 299 mHandler.obtainMessage(MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget(); 300 } 301 302 @Override 303 public void setAudioRoute(int route) { 304 mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget(); 305 } 306 307 @Override 308 public void conference(String callId, String otherCallId) { 309 if (mCallIdMapper.isValidCallId(callId) && 310 mCallIdMapper.isValidCallId(otherCallId)) { 311 SomeArgs args = SomeArgs.obtain(); 312 args.arg1 = callId; 313 args.arg2 = otherCallId; 314 mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget(); 315 } 316 } 317 318 @Override 319 public void splitFromConference(String callId) { 320 if (mCallIdMapper.isValidCallId(callId)) { 321 mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget(); 322 } 323 } 324 325 @Override 326 public void mergeConference(String callId) { 327 if (mCallIdMapper.isValidCallId(callId)) { 328 mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget(); 329 } 330 } 331 332 @Override 333 public void swapConference(String callId) { 334 if (mCallIdMapper.isValidCallId(callId)) { 335 mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget(); 336 } 337 } 338 339 @Override 340 public void turnOnProximitySensor() { 341 mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget(); 342 } 343 344 @Override 345 public void turnOffProximitySensor(boolean screenOnImmediately) { 346 mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget(); 347 } 348} 349