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 17 package com.android.server.telecom; 18 19 import android.os.Handler; 20 import android.os.Message; 21 import android.telecom.PhoneAccountHandle; 22 23 import com.android.internal.os.SomeArgs; 24 import 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 */ 31 class 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 mCallsManager.postDialContinue(call, msg.arg1 == 1); 106 call = mCallIdMapper.getCall(msg.obj); 107 if (call != null) { 108 mCallsManager.postDialContinue(call, msg.arg1 == 1); 109 } else { 110 Log.w(this, "postDialContinue, unknown call id: %s", msg.obj); 111 } 112 break; 113 case MSG_DISCONNECT_CALL: 114 call = mCallIdMapper.getCall(msg.obj); 115 if (call != null) { 116 mCallsManager.disconnectCall(call); 117 } else { 118 Log.w(this, "disconnectCall, unknown call id: %s", msg.obj); 119 } 120 break; 121 case MSG_HOLD_CALL: 122 call = mCallIdMapper.getCall(msg.obj); 123 if (call != null) { 124 mCallsManager.holdCall(call); 125 } else { 126 Log.w(this, "holdCall, unknown call id: %s", msg.obj); 127 } 128 break; 129 case MSG_UNHOLD_CALL: 130 call = mCallIdMapper.getCall(msg.obj); 131 if (call != null) { 132 mCallsManager.unholdCall(call); 133 } else { 134 Log.w(this, "unholdCall, unknown call id: %s", msg.obj); 135 } 136 break; 137 case MSG_PHONE_ACCOUNT_SELECTED: { 138 SomeArgs args = (SomeArgs) msg.obj; 139 try { 140 call = mCallIdMapper.getCall(args.arg1); 141 if (call != null) { 142 mCallsManager.phoneAccountSelected(call, (PhoneAccountHandle) args.arg2); 143 } else { 144 Log.w(this, "phoneAccountSelected, unknown call id: %s", args.arg1); 145 } 146 } finally { 147 args.recycle(); 148 } 149 break; 150 } 151 case MSG_MUTE: 152 mCallsManager.mute(msg.arg1 == 1); 153 break; 154 case MSG_SET_AUDIO_ROUTE: 155 mCallsManager.setAudioRoute(msg.arg1); 156 break; 157 case MSG_CONFERENCE: { 158 SomeArgs args = (SomeArgs) msg.obj; 159 try { 160 call = mCallIdMapper.getCall(args.arg1); 161 Call otherCall = mCallIdMapper.getCall(args.arg2); 162 if (call != null && otherCall != null) { 163 mCallsManager.conference(call, otherCall); 164 } else { 165 Log.w(this, "conference, unknown call id: %s", msg.obj); 166 } 167 } finally { 168 args.recycle(); 169 } 170 break; 171 } 172 case MSG_SPLIT_FROM_CONFERENCE: 173 call = mCallIdMapper.getCall(msg.obj); 174 if (call != null) { 175 call.splitFromConference(); 176 } else { 177 Log.w(this, "splitFromConference, unknown call id: %s", msg.obj); 178 } 179 break; 180 case MSG_TURN_ON_PROXIMITY_SENSOR: 181 mCallsManager.turnOnProximitySensor(); 182 break; 183 case MSG_TURN_OFF_PROXIMITY_SENSOR: 184 mCallsManager.turnOffProximitySensor((boolean) msg.obj); 185 break; 186 case MSG_MERGE_CONFERENCE: 187 call = mCallIdMapper.getCall(msg.obj); 188 if (call != null) { 189 call.mergeConference(); 190 } else { 191 Log.w(this, "mergeConference, unknown call id: %s", msg.obj); 192 } 193 break; 194 case MSG_SWAP_CONFERENCE: 195 call = mCallIdMapper.getCall(msg.obj); 196 if (call != null) { 197 call.swapConference(); 198 } else { 199 Log.w(this, "swapConference, unknown call id: %s", msg.obj); 200 } 201 break; 202 } 203 } 204 } 205 206 private final CallsManager mCallsManager; 207 private final Handler mHandler = new InCallAdapterHandler(); 208 private final CallIdMapper mCallIdMapper; 209 210 /** Persists the specified parameters. */ 211 public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper) { 212 ThreadUtil.checkOnMainThread(); 213 mCallsManager = callsManager; 214 mCallIdMapper = callIdMapper; 215 } 216 217 @Override 218 public void answerCall(String callId, int videoState) { 219 Log.d(this, "answerCall(%s,%d)", callId, videoState); 220 if (mCallIdMapper.isValidCallId(callId)) { 221 SomeArgs args = SomeArgs.obtain(); 222 args.arg1 = callId; 223 args.arg2 = videoState; 224 mHandler.obtainMessage(MSG_ANSWER_CALL, args).sendToTarget(); 225 } 226 } 227 228 @Override 229 public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) { 230 Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage); 231 if (mCallIdMapper.isValidCallId(callId)) { 232 SomeArgs args = SomeArgs.obtain(); 233 args.arg1 = callId; 234 args.argi1 = rejectWithMessage ? 1 : 0; 235 args.arg2 = textMessage; 236 mHandler.obtainMessage(MSG_REJECT_CALL, args).sendToTarget(); 237 } 238 } 239 240 @Override 241 public void playDtmfTone(String callId, char digit) { 242 Log.d(this, "playDtmfTone(%s,%c)", callId, digit); 243 if (mCallIdMapper.isValidCallId(callId)) { 244 mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, (int) digit, 0, callId).sendToTarget(); 245 } 246 } 247 248 @Override 249 public void stopDtmfTone(String callId) { 250 Log.d(this, "stopDtmfTone(%s)", callId); 251 if (mCallIdMapper.isValidCallId(callId)) { 252 mHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget(); 253 } 254 } 255 256 @Override 257 public void postDialContinue(String callId, boolean proceed) { 258 Log.d(this, "postDialContinue(%s)", callId); 259 if (mCallIdMapper.isValidCallId(callId)) { 260 mHandler.obtainMessage(MSG_POST_DIAL_CONTINUE, proceed ? 1 : 0, 0, callId).sendToTarget(); 261 } 262 } 263 264 @Override 265 public void disconnectCall(String callId) { 266 Log.v(this, "disconnectCall: %s", callId); 267 if (mCallIdMapper.isValidCallId(callId)) { 268 mHandler.obtainMessage(MSG_DISCONNECT_CALL, callId).sendToTarget(); 269 } 270 } 271 272 @Override 273 public void holdCall(String callId) { 274 if (mCallIdMapper.isValidCallId(callId)) { 275 mHandler.obtainMessage(MSG_HOLD_CALL, callId).sendToTarget(); 276 } 277 } 278 279 @Override 280 public void unholdCall(String callId) { 281 if (mCallIdMapper.isValidCallId(callId)) { 282 mHandler.obtainMessage(MSG_UNHOLD_CALL, callId).sendToTarget(); 283 } 284 } 285 286 @Override 287 public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle) { 288 if (mCallIdMapper.isValidCallId(callId)) { 289 SomeArgs args = SomeArgs.obtain(); 290 args.arg1 = callId; 291 args.arg2 = accountHandle; 292 mHandler.obtainMessage(MSG_PHONE_ACCOUNT_SELECTED, args).sendToTarget(); 293 } 294 } 295 296 @Override 297 public void mute(boolean shouldMute) { 298 mHandler.obtainMessage(MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget(); 299 } 300 301 @Override 302 public void setAudioRoute(int route) { 303 mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, route, 0).sendToTarget(); 304 } 305 306 @Override 307 public void conference(String callId, String otherCallId) { 308 if (mCallIdMapper.isValidCallId(callId) && 309 mCallIdMapper.isValidCallId(otherCallId)) { 310 SomeArgs args = SomeArgs.obtain(); 311 args.arg1 = callId; 312 args.arg2 = otherCallId; 313 mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget(); 314 } 315 } 316 317 @Override 318 public void splitFromConference(String callId) { 319 if (mCallIdMapper.isValidCallId(callId)) { 320 mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget(); 321 } 322 } 323 324 @Override 325 public void mergeConference(String callId) { 326 if (mCallIdMapper.isValidCallId(callId)) { 327 mHandler.obtainMessage(MSG_MERGE_CONFERENCE, callId).sendToTarget(); 328 } 329 } 330 331 @Override 332 public void swapConference(String callId) { 333 if (mCallIdMapper.isValidCallId(callId)) { 334 mHandler.obtainMessage(MSG_SWAP_CONFERENCE, callId).sendToTarget(); 335 } 336 } 337 338 @Override 339 public void turnOnProximitySensor() { 340 mHandler.obtainMessage(MSG_TURN_ON_PROXIMITY_SENSOR).sendToTarget(); 341 } 342 343 @Override 344 public void turnOffProximitySensor(boolean screenOnImmediately) { 345 mHandler.obtainMessage(MSG_TURN_OFF_PROXIMITY_SENSOR, screenOnImmediately).sendToTarget(); 346 } 347 } 348