1 /*
2 * Copyright (C) 2025 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 #define FAILURE_DEBUG_PREFIX "RadioVoice"
18
19 #include "RadioVoice.h"
20
21 #include "atCmds.h"
22 #include "debug.h"
23 #include "makeRadioResponseInfo.h"
24
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace radio {
29 namespace implementation {
30
RadioVoice(std::shared_ptr<AtChannel> atChannel)31 RadioVoice::RadioVoice(std::shared_ptr<AtChannel> atChannel) : mAtChannel(std::move(atChannel)) {
32 }
33
acceptCall(const int32_t serial)34 ScopedAStatus RadioVoice::acceptCall(const int32_t serial) {
35 mAtChannel->queueRequester([this, serial]
36 (const AtChannel::RequestPipe requestPipe) -> bool {
37 requestPipe(atCmds::acceptCall);
38 NOT_NULL(mRadioVoiceResponse)->acceptCallResponse(
39 makeRadioResponseInfo(serial));
40 return true;
41 });
42
43 return ScopedAStatus::ok();
44 }
45
cancelPendingUssd(const int32_t serial)46 ScopedAStatus RadioVoice::cancelPendingUssd(const int32_t serial) {
47 mAtChannel->queueRequester([this, serial]
48 (const AtChannel::RequestPipe requestPipe) -> bool {
49 requestPipe(atCmds::cancelUssd);
50 NOT_NULL(mRadioVoiceResponse)->cancelPendingUssdResponse(
51 makeRadioResponseInfo(serial));
52 return true;
53 });
54
55 return ScopedAStatus::ok();
56 }
57
conference(const int32_t serial)58 ScopedAStatus RadioVoice::conference(const int32_t serial) {
59 mAtChannel->queueRequester([this, serial]
60 (const AtChannel::RequestPipe requestPipe) -> bool {
61 requestPipe(atCmds::conference);
62 NOT_NULL(mRadioVoiceResponse)->conferenceResponse(
63 makeRadioResponseInfo(serial));
64 return true;
65 });
66
67 return ScopedAStatus::ok();
68 }
69
dial(const int32_t serial,const voice::Dial & dialInfo)70 ScopedAStatus RadioVoice::dial(const int32_t serial,
71 const voice::Dial& dialInfo) {
72 static const char* const kFunc = __func__;
73 mAtChannel->queueRequester([this, serial, dialInfo]
74 (const AtChannel::RequestPipe requestPipe) -> bool {
75 using namespace std::literals;
76 using CmeError = AtResponse::CmeError;
77 using voice::Dial;
78
79 RadioError status = RadioError::NONE;
80
81 std::string_view clir;
82 switch (dialInfo.clir) {
83 case Dial::CLIR_INVOCATION:
84 clir = "I"sv;
85 break;
86 case Dial::CLIR_SUPPRESSION:
87 clir = "i"sv;
88 break;
89 default:
90 case Dial::CLIR_DEFAULT:
91 // clir is the empty string
92 break;
93 }
94
95 const std::string request = std::format("ATD{0:s}{1:s};",
96 dialInfo.address, clir);
97
98 const AtResponsePtr response =
99 mAtConversation(requestPipe, request,
100 [](const AtResponse& response) -> bool {
101 return response.isOK() || response.holds<CmeError>();
102 });
103 if (!response || response->isParseError()) {
104 status = FAILURE(RadioError::INTERNAL_ERR);
105 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
106 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
107 } else if (!response->isOK()) {
108 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
109 }
110
111 NOT_NULL(mRadioVoiceResponse)->dialResponse(
112 makeRadioResponseInfo(serial, status));
113 return status != RadioError::INTERNAL_ERR;
114 });
115
116 return ScopedAStatus::ok();
117 }
118
emergencyDial(const int32_t serial,const voice::Dial & dialInfo,const int32_t categories,const std::vector<std::string> &,const voice::EmergencyCallRouting routing,const bool,const bool)119 ScopedAStatus RadioVoice::emergencyDial(const int32_t serial,
120 const voice::Dial& dialInfo,
121 const int32_t categories,
122 const std::vector<std::string>& /*urns*/,
123 const voice::EmergencyCallRouting routing,
124 const bool /*hasKnownUserIntentEmergency*/,
125 const bool /*isTesting*/) {
126 static const char* const kFunc = __func__;
127 mAtChannel->queueRequester([this, serial, dialInfo, categories, routing]
128 (const AtChannel::RequestPipe requestPipe) -> bool {
129 using namespace std::literals;
130 using CmeError = AtResponse::CmeError;
131 using voice::Dial;
132 using voice::EmergencyCallRouting;
133
134 RadioError status = RadioError::NONE;
135
136 std::string_view clir;
137 switch (dialInfo.clir) {
138 case Dial::CLIR_INVOCATION:
139 clir = "I"sv;
140 break;
141 case Dial::CLIR_SUPPRESSION:
142 clir = "i"sv;
143 break;
144 default:
145 case Dial::CLIR_DEFAULT:
146 // clir is the empty string
147 break;
148 }
149
150 std::string request;
151 switch (routing) {
152 case EmergencyCallRouting::EMERGENCY:
153 case EmergencyCallRouting::UNKNOWN:
154 if (categories) {
155 request = std::format("ATD{0:s}@{1:d},#{2:s};",
156 dialInfo.address, categories, clir);
157 } else {
158 request = std::format("ATD{0:s}@,#{1:s};", dialInfo.address, clir);
159 }
160 break;
161
162 default:
163 case EmergencyCallRouting::NORMAL:
164 request = std::format("ATD{0:s}{1:s};", dialInfo.address, clir);
165 break;
166 }
167
168 const AtResponsePtr response =
169 mAtConversation(requestPipe, request,
170 [](const AtResponse& response) -> bool {
171 return response.isOK() || response.holds<CmeError>();
172 });
173 if (!response || response->isParseError()) {
174 status = FAILURE(RadioError::INTERNAL_ERR);
175 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
176 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
177 } else if (!response->isOK()) {
178 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
179 }
180
181 NOT_NULL(mRadioVoiceResponse)->emergencyDialResponse(
182 makeRadioResponseInfo(serial, status));
183 return status != RadioError::INTERNAL_ERR;
184 });
185
186 return ScopedAStatus::ok();
187 }
188
exitEmergencyCallbackMode(const int32_t serial)189 ScopedAStatus RadioVoice::exitEmergencyCallbackMode(const int32_t serial) {
190 static const char* const kFunc = __func__;
191 mAtChannel->queueRequester([this, serial]
192 (const AtChannel::RequestPipe requestPipe) -> bool {
193 using CmeError = AtResponse::CmeError;
194
195 RadioError status = RadioError::NONE;
196
197 const AtResponsePtr response =
198 mAtConversation(requestPipe, atCmds::exitEmergencyMode,
199 [](const AtResponse& response) -> bool {
200 return response.isOK() || response.holds<CmeError>();
201 });
202 if (!response || response->isParseError()) {
203 status = FAILURE(RadioError::INTERNAL_ERR);
204 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
205 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
206 } else if (!response->isOK()) {
207 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
208 }
209
210 NOT_NULL(mRadioVoiceResponse)->exitEmergencyCallbackModeResponse(
211 makeRadioResponseInfo(serial, status));
212 return status != RadioError::INTERNAL_ERR;
213 });
214
215 return ScopedAStatus::ok();
216 }
217
explicitCallTransfer(const int32_t serial)218 ScopedAStatus RadioVoice::explicitCallTransfer(const int32_t serial) {
219 // matches reference-ril.c
220 NOT_NULL(mRadioVoiceResponse)->explicitCallTransferResponse(
221 makeRadioResponseInfoUnsupported(
222 serial, FAILURE_DEBUG_PREFIX, __func__));
223 return ScopedAStatus::ok();
224 }
225
getCallForwardStatus(const int32_t serial,const voice::CallForwardInfo & callInfo)226 ScopedAStatus RadioVoice::getCallForwardStatus(const int32_t serial,
227 const voice::CallForwardInfo& callInfo) {
228 static const char* const kFunc = __func__;
229 mAtChannel->queueRequester([this, serial, callInfo](const AtChannel::RequestPipe requestPipe) -> bool {
230 using CCFCU = AtResponse::CCFCU;
231 using CmeError = AtResponse::CmeError;
232 using voice::CallForwardInfo;
233
234 RadioError status = RadioError::NONE;
235 std::vector<CallForwardInfo> callForwardInfos;
236
237 const std::string request = std::format(
238 "AT+CCFCU={0:d},{1:d},{2:d},{3:d},\"{4:s}\",{5:d}",
239 callInfo.reason, 2, 2, callInfo.toa,
240 callInfo.number, callInfo.serviceClass);
241
242 const AtResponsePtr response =
243 mAtConversation(requestPipe, request,
244 [](const AtResponse& response) -> bool {
245 return response.holds<CCFCU>() ||
246 response.isOK() ||
247 response.holds<CmeError>();
248 });
249 if (!response || response->isParseError()) {
250 status = FAILURE(RadioError::INTERNAL_ERR);
251 } else if (const CCFCU* ccfcu = response->get_if<CCFCU>()) {
252 callForwardInfos = ccfcu->callForwardInfos;
253 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
254 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
255 } else if (!response->isOK()) {
256 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
257 }
258
259 NOT_NULL(mRadioVoiceResponse)->getCallForwardStatusResponse(
260 makeRadioResponseInfo(serial, status),
261 std::move(callForwardInfos));
262 return status != RadioError::INTERNAL_ERR;
263 });
264
265 return ScopedAStatus::ok();
266 }
267
getCallWaiting(const int32_t serial,const int32_t serviceClass)268 ScopedAStatus RadioVoice::getCallWaiting(const int32_t serial,
269 const int32_t serviceClass) {
270 static const char* const kFunc = __func__;
271 mAtChannel->queueRequester([this, serial, serviceClass]
272 (const AtChannel::RequestPipe requestPipe) -> bool {
273 using CCWA = AtResponse::CCWA;
274 using CmeError = AtResponse::CmeError;
275
276 RadioError status = RadioError::NONE;
277 bool enable = false;
278 int serviceClassOut = -1;
279
280 const std::string request =
281 std::format("AT+CCWA={0:d},{1:d},{2:d}",
282 1, 2, serviceClass);
283 const AtResponsePtr response =
284 mAtConversation(requestPipe, request,
285 [](const AtResponse& response) -> bool {
286 return response.holds<CCWA>() ||
287 response.holds<CmeError>();
288 });
289 if (!response || response->isParseError()) {
290 status = FAILURE(RadioError::INTERNAL_ERR);
291 } else if (const CCWA* ccwa = response->get_if<CCWA>()) {
292 enable = ccwa->enable;
293 serviceClassOut = ccwa->serviceClass;
294 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
295 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
296 } else {
297 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
298 }
299
300 NOT_NULL(mRadioVoiceResponse)->getCallWaitingResponse(
301 makeRadioResponseInfo(serial, status), enable, serviceClassOut);
302 return status != RadioError::INTERNAL_ERR;
303 });
304
305 return ScopedAStatus::ok();
306 }
307
getClip(const int32_t serial)308 ScopedAStatus RadioVoice::getClip(const int32_t serial) {
309 static const char* const kFunc = __func__;
310 mAtChannel->queueRequester([this, serial]
311 (const AtChannel::RequestPipe requestPipe) -> bool {
312 using CLIP = AtResponse::CLIP;
313 using CmeError = AtResponse::CmeError;
314 using ClipStatus = voice::ClipStatus;
315
316 RadioError status = RadioError::NONE;
317 ClipStatus clipStatus = ClipStatus::UNKNOWN;
318
319 const AtResponsePtr response =
320 mAtConversation(requestPipe, atCmds::getClip,
321 [](const AtResponse& response) -> bool {
322 return response.holds<CLIP>() ||
323 response.holds<CmeError>();
324 });
325 if (!response || response->isParseError()) {
326 status = FAILURE(RadioError::INTERNAL_ERR);
327 } else if (const CLIP* clip = response->get_if<CLIP>()) {
328 clipStatus = clip->status;
329 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
330 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
331 } else {
332 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
333 }
334
335 NOT_NULL(mRadioVoiceResponse)->getClipResponse(
336 makeRadioResponseInfo(serial, status), clipStatus);
337 return status != RadioError::INTERNAL_ERR;
338 });
339
340 return ScopedAStatus::ok();
341 }
342
getClir(const int32_t serial)343 ScopedAStatus RadioVoice::getClir(const int32_t serial) {
344 static const char* const kFunc = __func__;
345 mAtChannel->queueRequester([this, serial]
346 (const AtChannel::RequestPipe requestPipe) -> bool {
347 using CLIR = AtResponse::CLIR;
348 using CmeError = AtResponse::CmeError;
349
350 RadioError status = RadioError::NONE;
351 int n = -1;
352 int m = -1;
353
354 const AtResponsePtr response =
355 mAtConversation(requestPipe, atCmds::getClir,
356 [](const AtResponse& response) -> bool {
357 return response.holds<CLIR>() ||
358 response.holds<CmeError>();
359 });
360 if (!response || response->isParseError()) {
361 status = FAILURE(RadioError::INTERNAL_ERR);
362 } else if (const CLIR* clir = response->get_if<CLIR>()) {
363 n = clir->n;
364 m = clir->m;
365 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
366 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
367 } else {
368 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
369 }
370
371 NOT_NULL(mRadioVoiceResponse)->getClirResponse(
372 makeRadioResponseInfo(serial, status), n, m);
373 return status != RadioError::INTERNAL_ERR;
374 });
375
376 return ScopedAStatus::ok();
377 }
378
getCurrentCalls(const int32_t serial)379 ScopedAStatus RadioVoice::getCurrentCalls(const int32_t serial) {
380 static const char* const kFunc = __func__;
381 mAtChannel->queueRequester([this, serial](const AtChannel::RequestPipe requestPipe) -> bool {
382 using CLCC = AtResponse::CLCC;
383 using CmeError = AtResponse::CmeError;
384
385 RadioError status = RadioError::NONE;
386 std::vector<voice::Call> calls;
387
388 const AtResponsePtr response =
389 mAtConversation(requestPipe, atCmds::getCurrentCalls,
390 [](const AtResponse& response) -> bool {
391 return response.holds<CLCC>() ||
392 response.isOK() ||
393 response.holds<CmeError>();
394 });
395 if (!response || response->isParseError()) {
396 status = FAILURE(RadioError::INTERNAL_ERR);
397 } else if (const CLCC* clcc = response->get_if<CLCC>()) {
398 calls = clcc->calls;
399 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
400 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
401 } else if (!response->isOK()) {
402 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
403 }
404
405 NOT_NULL(mRadioVoiceResponse)->getCurrentCallsResponse(
406 makeRadioResponseInfo(serial, status), std::move(calls));
407 return status != RadioError::INTERNAL_ERR;
408 });
409
410 return ScopedAStatus::ok();
411 }
412
getLastCallFailCause(const int32_t serial)413 ScopedAStatus RadioVoice::getLastCallFailCause(const int32_t serial) {
414 // matches reference-ril.c
415 NOT_NULL(mRadioVoiceResponse)->getLastCallFailCauseResponse(
416 makeRadioResponseInfoUnsupported(
417 serial, FAILURE_DEBUG_PREFIX, __func__), {});
418 return ScopedAStatus::ok();
419 }
420
getMute(const int32_t serial)421 ScopedAStatus RadioVoice::getMute(const int32_t serial) {
422 static const char* const kFunc = __func__;
423 mAtChannel->queueRequester([this, serial](const AtChannel::RequestPipe requestPipe) -> bool {
424 using CMUT = AtResponse::CMUT;
425 using CmeError = AtResponse::CmeError;
426
427 RadioError status = RadioError::NONE;
428 bool isMuted = false;
429
430 const AtResponsePtr response =
431 mAtConversation(requestPipe, atCmds::getCurrentCalls,
432 [](const AtResponse& response) -> bool {
433 return response.holds<CMUT>() ||
434 response.holds<CmeError>();
435 });
436 if (!response || response->isParseError()) {
437 NOT_NULL(mRadioVoiceResponse)->getCurrentCallsResponse(
438 makeRadioResponseInfo(serial, FAILURE(RadioError::INTERNAL_ERR)), {});
439 return false;
440 } else if (const CMUT* cmut = response->get_if<CMUT>()) {
441 isMuted = cmut->on;
442 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
443 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
444 } else if (!response->isOK()) {
445 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
446 }
447
448
449 NOT_NULL(mRadioVoiceResponse)->getMuteResponse(
450 makeRadioResponseInfo(serial, status), isMuted);
451 return status != RadioError::INTERNAL_ERR;
452 });
453
454 return ScopedAStatus::ok();
455 }
456
getPreferredVoicePrivacy(const int32_t serial)457 ScopedAStatus RadioVoice::getPreferredVoicePrivacy(const int32_t serial) {
458 // matches reference-ril.c
459 NOT_NULL(mRadioVoiceResponse)->getPreferredVoicePrivacyResponse(
460 makeRadioResponseInfoUnsupported(
461 serial, FAILURE_DEBUG_PREFIX, __func__), false);
462 return ScopedAStatus::ok();
463 }
464
getTtyMode(const int32_t serial)465 ScopedAStatus RadioVoice::getTtyMode(const int32_t serial) {
466 NOT_NULL(mRadioVoiceResponse)->getTtyModeResponse(
467 makeRadioResponseInfo(serial), voice::TtyMode::FULL);
468 return ScopedAStatus::ok();
469 }
470
handleStkCallSetupRequestFromSim(const int32_t serial,const bool)471 ScopedAStatus RadioVoice::handleStkCallSetupRequestFromSim(const int32_t serial,
472 const bool /*accept*/) {
473 // matches reference-ril.c
474 NOT_NULL(mRadioVoiceResponse)->handleStkCallSetupRequestFromSimResponse(
475 makeRadioResponseInfoUnsupported(
476 serial, FAILURE_DEBUG_PREFIX, __func__));
477 return ScopedAStatus::ok();
478 }
479
hangup(const int32_t serial,const int32_t gsmIndex)480 ScopedAStatus RadioVoice::hangup(const int32_t serial,
481 const int32_t gsmIndex) {
482 static const char* const kFunc = __func__;
483 mAtChannel->queueRequester([this, serial, gsmIndex]
484 (const AtChannel::RequestPipe requestPipe) -> bool {
485 requestPipe(std::format("AT+CHLD=1{0:d}", gsmIndex));
486 NOT_NULL(mRadioVoiceResponse)->hangupConnectionResponse(
487 makeRadioResponseInfo(serial));
488 return true;
489 });
490
491 return ScopedAStatus::ok();
492 }
493
hangupForegroundResumeBackground(const int32_t serial)494 ScopedAStatus RadioVoice::hangupForegroundResumeBackground(const int32_t serial) {
495 mAtChannel->queueRequester([this, serial]
496 (const AtChannel::RequestPipe requestPipe) -> bool {
497 requestPipe(atCmds::hangupForeground);
498 NOT_NULL(mRadioVoiceResponse)->hangupForegroundResumeBackgroundResponse(
499 makeRadioResponseInfo(serial));
500 return true;
501 });
502
503 return ScopedAStatus::ok();
504 }
505
hangupWaitingOrBackground(const int32_t serial)506 ScopedAStatus RadioVoice::hangupWaitingOrBackground(const int32_t serial) {
507 mAtChannel->queueRequester([this, serial]
508 (const AtChannel::RequestPipe requestPipe) -> bool {
509 requestPipe(atCmds::hangupWaiting);
510 NOT_NULL(mRadioVoiceResponse)->hangupWaitingOrBackgroundResponse(
511 makeRadioResponseInfo(serial));
512 return true;
513 });
514
515 return ScopedAStatus::ok();
516 }
517
isVoNrEnabled(const int32_t serial)518 ScopedAStatus RadioVoice::isVoNrEnabled(const int32_t serial) {
519 NOT_NULL(mRadioVoiceResponse)->isVoNrEnabledResponse(
520 makeRadioResponseInfoNOP(serial), false);
521 return ScopedAStatus::ok();
522 }
523
rejectCall(const int32_t serial)524 ScopedAStatus RadioVoice::rejectCall(const int32_t serial) {
525 mAtChannel->queueRequester([this, serial]
526 (const AtChannel::RequestPipe requestPipe) -> bool {
527 requestPipe(atCmds::rejectCall);
528 NOT_NULL(mRadioVoiceResponse)->rejectCallResponse(
529 makeRadioResponseInfo(serial));
530 return true;
531 });
532
533 return ScopedAStatus::ok();
534 }
535
sendBurstDtmf(const int32_t serial,const std::string &,const int32_t,const int32_t)536 ScopedAStatus RadioVoice::sendBurstDtmf(const int32_t serial,
537 const std::string& /*dtmf*/,
538 const int32_t /*on*/,
539 const int32_t /*off*/) {
540 // matches reference-ril.c
541 NOT_NULL(mRadioVoiceResponse)->sendBurstDtmfResponse(
542 makeRadioResponseInfoUnsupported(
543 serial, FAILURE_DEBUG_PREFIX, __func__));
544 return ScopedAStatus::ok();
545 }
546
sendCdmaFeatureCode(const int32_t serial,const std::string &)547 ScopedAStatus RadioVoice::sendCdmaFeatureCode(const int32_t serial,
548 const std::string& /*fcode*/) {
549 // matches reference-ril.c
550 NOT_NULL(mRadioVoiceResponse)->sendCdmaFeatureCodeResponse(
551 makeRadioResponseInfoUnsupported(
552 serial, FAILURE_DEBUG_PREFIX, __func__));
553 return ScopedAStatus::ok();
554 }
555
sendDtmf(const int32_t serial,const std::string & s)556 ScopedAStatus RadioVoice::sendDtmf(const int32_t serial,
557 const std::string& s) {
558 static const char* const kFunc = __func__;
559 mAtChannel->queueRequester([this, serial, s]
560 (const AtChannel::RequestPipe requestPipe) -> bool {
561 requestPipe(std::format("AT+VTS={0:s}", s));
562 NOT_NULL(mRadioVoiceResponse)->sendDtmfResponse(
563 makeRadioResponseInfo(serial));
564 return true;
565 });
566
567 return ScopedAStatus::ok();
568 }
569
sendUssd(const int32_t serial,const std::string & ussd)570 ScopedAStatus RadioVoice::sendUssd(const int32_t serial,
571 const std::string& ussd) {
572 static const char* const kFunc = __func__;
573 mAtChannel->queueRequester([this, serial, ussd]
574 (const AtChannel::RequestPipe requestPipe) -> bool {
575 requestPipe(std::format("AT+CUSD=1,\"%s\"", ussd));
576 NOT_NULL(mRadioVoiceResponse)->sendUssdResponse(
577 makeRadioResponseInfo(serial));
578 return true;
579 });
580
581 return ScopedAStatus::ok();
582 }
583
separateConnection(const int32_t serial,const int32_t gsmIndex)584 ScopedAStatus RadioVoice::separateConnection(const int32_t serial,
585 const int32_t gsmIndex) {
586 static const char* const kFunc = __func__;
587 mAtChannel->queueRequester([this, serial, gsmIndex]
588 (const AtChannel::RequestPipe requestPipe) -> bool {
589 if ((gsmIndex > 0) && (gsmIndex < 10)) {
590 requestPipe(std::format("AT+CHLD=2{0:d}", gsmIndex));
591 NOT_NULL(mRadioVoiceResponse)->separateConnectionResponse(
592 makeRadioResponseInfo(serial));
593 } else {
594 NOT_NULL(mRadioVoiceResponse)->separateConnectionResponse(
595 makeRadioResponseInfo(serial, FAILURE(RadioError::GENERIC_FAILURE)));
596 }
597
598 return true;
599 });
600
601 return ScopedAStatus::ok();
602 }
603
setCallForward(const int32_t serial,const voice::CallForwardInfo & callInfo)604 ScopedAStatus RadioVoice::setCallForward(const int32_t serial,
605 const voice::CallForwardInfo& callInfo) {
606 static const char* const kFunc = __func__;
607 mAtChannel->queueRequester([this, serial, callInfo](const AtChannel::RequestPipe requestPipe) -> bool {
608 using CmeError = AtResponse::CmeError;
609
610 RadioError status = RadioError::NONE;
611
612 std::string request = std::format(
613 "AT+CCFCU={0:d},{1:d},{2:d},{3:d},\"{4:s}\",{5:d}",
614 callInfo.reason, callInfo.status, 2, callInfo.toa,
615 callInfo.number, callInfo.serviceClass);
616 if ((callInfo.timeSeconds > 0) && (callInfo.status == 3)) {
617 request += std::format(",\"\",\"\",,{0:d}", callInfo.timeSeconds);
618 } else if (callInfo.serviceClass) {
619 request += ",\"\"";
620 }
621
622 const AtResponsePtr response =
623 mAtConversation(requestPipe, request,
624 [](const AtResponse& response) -> bool {
625 return response.isOK() ||
626 response.holds<CmeError>();
627 });
628 if (!response || response->isParseError()) {
629 status = FAILURE(RadioError::INTERNAL_ERR);
630 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
631 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
632 } else if (!response->isOK()) {
633 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
634 }
635
636 NOT_NULL(mRadioVoiceResponse)->setCallForwardResponse(
637 makeRadioResponseInfo(serial, status));
638 return status != RadioError::INTERNAL_ERR;
639 });
640
641 return ScopedAStatus::ok();
642 }
643
setCallWaiting(const int32_t serial,const bool enable,const int32_t serviceClass)644 ScopedAStatus RadioVoice::setCallWaiting(const int32_t serial,
645 const bool enable,
646 const int32_t serviceClass) {
647 static const char* const kFunc = __func__;
648 mAtChannel->queueRequester([this, serial, enable, serviceClass]
649 (const AtChannel::RequestPipe requestPipe) -> bool {
650 using CmeError = AtResponse::CmeError;
651
652 RadioError status = RadioError::NONE;
653
654 const std::string request =
655 std::format("AT+CCWA={0:d},{1:d},{2:d}", 1, (enable ? 1 : 0),
656 serviceClass);
657 const AtResponsePtr response =
658 mAtConversation(requestPipe, request,
659 [](const AtResponse& response) -> bool {
660 return response.isOK() ||
661 response.holds<CmeError>();
662 });
663 if (!response || response->isParseError()) {
664 status = FAILURE(RadioError::INTERNAL_ERR);
665 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
666 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
667 } else if (!response->isOK()) {
668 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
669 }
670
671 NOT_NULL(mRadioVoiceResponse)->setCallWaitingResponse(
672 makeRadioResponseInfo(serial, status));
673 return status != RadioError::INTERNAL_ERR;
674 });
675
676
677 return ScopedAStatus::ok();
678 }
679
setClir(const int32_t serial,const int32_t clirStatus)680 ScopedAStatus RadioVoice::setClir(const int32_t serial, const int32_t clirStatus) {
681 static const char* const kFunc = __func__;
682 mAtChannel->queueRequester([this, serial, clirStatus]
683 (const AtChannel::RequestPipe requestPipe) -> bool {
684 using CmeError = AtResponse::CmeError;
685
686 RadioError status = RadioError::NONE;
687
688 const std::string request = std::format("AT+CLIR: {0:d}", clirStatus);
689 const AtResponsePtr response =
690 mAtConversation(requestPipe, request,
691 [](const AtResponse& response) -> bool {
692 return response.isOK() ||
693 response.holds<CmeError>();
694 });
695 if (!response || response->isParseError()) {
696 status = FAILURE(RadioError::INTERNAL_ERR);
697 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
698 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
699 } else if (!response->isOK()) {
700 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
701 }
702
703 NOT_NULL(mRadioVoiceResponse)->setClirResponse(
704 makeRadioResponseInfo(serial, status));
705 return status != RadioError::INTERNAL_ERR;
706 });
707
708 return ScopedAStatus::ok();
709 }
710
setMute(const int32_t serial,const bool enable)711 ScopedAStatus RadioVoice::setMute(const int32_t serial,
712 const bool enable) {
713 static const char* const kFunc = __func__;
714 mAtChannel->queueRequester([this, serial, enable]
715 (const AtChannel::RequestPipe requestPipe) -> bool {
716 using CmeError = AtResponse::CmeError;
717 RadioError status = RadioError::NONE;
718
719 const std::string request =
720 std::format("AT+CMUT={0:d}", (enable ? 1 : 0));
721 const AtResponsePtr response =
722 mAtConversation(requestPipe, request,
723 [](const AtResponse& response) -> bool {
724 return response.isOK() ||
725 response.holds<CmeError>();
726 });
727 if (!response || response->isParseError()) {
728 NOT_NULL(mRadioVoiceResponse)->getCurrentCallsResponse(
729 makeRadioResponseInfo(serial, FAILURE(RadioError::INTERNAL_ERR)), {});
730 return false;
731 } else if (const CmeError* cmeError = response->get_if<CmeError>()) {
732 status = cmeError->getErrorAndLog(FAILURE_DEBUG_PREFIX, kFunc, __LINE__);
733 } else if (!response->isOK()) {
734 response->unexpected(FAILURE_DEBUG_PREFIX, kFunc);
735 }
736
737 NOT_NULL(mRadioVoiceResponse)->setMuteResponse(
738 makeRadioResponseInfo(serial, status));
739 return status != RadioError::INTERNAL_ERR;
740 });
741
742 return ScopedAStatus::ok();
743 }
744
setPreferredVoicePrivacy(const int32_t serial,const bool)745 ScopedAStatus RadioVoice::setPreferredVoicePrivacy(const int32_t serial,
746 const bool /*enable*/) {
747 // matches reference-ril.c
748 NOT_NULL(mRadioVoiceResponse)->setPreferredVoicePrivacyResponse(
749 makeRadioResponseInfoNOP(serial));
750 return ScopedAStatus::ok();
751 }
752
setTtyMode(const int32_t serial,voice::TtyMode)753 ScopedAStatus RadioVoice::setTtyMode(const int32_t serial, voice::TtyMode /*mode*/) {
754 NOT_NULL(mRadioVoiceResponse)->setTtyModeResponse(
755 makeRadioResponseInfoNOP(serial));
756 return ScopedAStatus::ok();
757 }
758
setVoNrEnabled(const int32_t serial,const bool enable)759 ScopedAStatus RadioVoice::setVoNrEnabled(const int32_t serial, const bool enable) {
760 // matches reference-ril.c
761 NOT_NULL(mRadioVoiceResponse)->setVoNrEnabledResponse(
762 makeRadioResponseInfo(serial, enable ?
763 FAILURE(RadioError::REQUEST_NOT_SUPPORTED) : RadioError::NONE));
764 return ScopedAStatus::ok();
765 }
766
startDtmf(const int32_t serial,const std::string &)767 ScopedAStatus RadioVoice::startDtmf(const int32_t serial, const std::string& /*s*/) {
768 // matches reference-ril.c
769 NOT_NULL(mRadioVoiceResponse)->startDtmfResponse(
770 makeRadioResponseInfoUnsupported(
771 serial, FAILURE_DEBUG_PREFIX, __func__));
772 return ScopedAStatus::ok();
773 }
774
stopDtmf(const int32_t serial)775 ScopedAStatus RadioVoice::stopDtmf(const int32_t serial) {
776 // matches reference-ril.c
777 NOT_NULL(mRadioVoiceResponse)->stopDtmfResponse(
778 makeRadioResponseInfoUnsupported(
779 serial, FAILURE_DEBUG_PREFIX, __func__));
780 return ScopedAStatus::ok();
781 }
782
switchWaitingOrHoldingAndActive(const int32_t serial)783 ScopedAStatus RadioVoice::switchWaitingOrHoldingAndActive(const int32_t serial) {
784 mAtChannel->queueRequester([this, serial]
785 (const AtChannel::RequestPipe requestPipe) -> bool {
786 requestPipe(atCmds::switchWaiting);
787 NOT_NULL(mRadioVoiceResponse)->switchWaitingOrHoldingAndActiveResponse(
788 makeRadioResponseInfo(serial));
789 return true;
790 });
791 return ScopedAStatus::ok();
792 }
793
atResponseSink(const AtResponsePtr & response)794 void RadioVoice::atResponseSink(const AtResponsePtr& response) {
795 if (!mAtConversation.send(response)) {
796 response->visit([this](const auto& msg){ handleUnsolicited(msg); });
797 }
798 }
799
handleUnsolicited(const AtResponse::RING &)800 void RadioVoice::handleUnsolicited(const AtResponse::RING&) {
801 if (mRadioVoiceIndication) {
802 mRadioVoiceIndication->callRing(RadioIndicationType::UNSOLICITED, true, {});
803 mRadioVoiceIndication->callStateChanged(RadioIndicationType::UNSOLICITED);
804 }
805 }
806
handleUnsolicited(const AtResponse::WSOS & wsos)807 void RadioVoice::handleUnsolicited(const AtResponse::WSOS& wsos) {
808 if (mRadioVoiceIndication) {
809 if (wsos.isEmergencyMode) {
810 mRadioVoiceIndication->enterEmergencyCallbackMode(
811 RadioIndicationType::UNSOLICITED);
812 } else {
813 mRadioVoiceIndication->exitEmergencyCallbackMode(
814 RadioIndicationType::UNSOLICITED);
815 }
816 }
817 }
818
responseAcknowledgement()819 ScopedAStatus RadioVoice::responseAcknowledgement() {
820 return ScopedAStatus::ok();
821 }
822
setResponseFunctions(const std::shared_ptr<voice::IRadioVoiceResponse> & radioVoiceResponse,const std::shared_ptr<voice::IRadioVoiceIndication> & radioVoiceIndication)823 ScopedAStatus RadioVoice::setResponseFunctions(
824 const std::shared_ptr<voice::IRadioVoiceResponse>& radioVoiceResponse,
825 const std::shared_ptr<voice::IRadioVoiceIndication>& radioVoiceIndication) {
826 mRadioVoiceResponse = NOT_NULL(radioVoiceResponse);
827 mRadioVoiceIndication = NOT_NULL(radioVoiceIndication);
828 return ScopedAStatus::ok();
829 }
830
831 } // namespace implementation
832 } // namespace radio
833 } // namespace hardware
834 } // namespace android
835 } // namespace aidl
836