/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony; import android.os.RemoteException; import android.telephony.PhoneNumberUtils; import android.telephony.Rlog; import android.telephony.emergency.EmergencyNumber; import java.util.ArrayList; /** * A holder for IRadioVoice. * Use getAidl to get IRadioVoice and call the AIDL implementations of the HAL APIs. */ public class RadioVoiceProxy extends RadioServiceProxy { private static final String TAG = "RadioVoiceProxy"; private volatile android.hardware.radio.voice.IRadioVoice mVoiceProxy = null; /** * Set IRadioVoice as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param voice IRadioVoice implementation * * @return updated HAL version */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.voice.IRadioVoice voice) { HalVersion version = halVersion; try { version = RIL.getServiceHalVersion(voice.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } mHalVersion = version; mVoiceProxy = voice; mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; } /** * Get the AIDL implementation of RadioVoiceProxy * @return IRadioVoice implementation */ public android.hardware.radio.voice.IRadioVoice getAidl() { return mVoiceProxy; } /** * Reset RadioVoiceProxy */ @Override public void clear() { super.clear(); mVoiceProxy = null; } /** * Check whether a RadioVoice implementation exists * @return true if there is neither a HIDL nor AIDL implementation */ @Override public boolean isEmpty() { return mRadioProxy == null && mVoiceProxy == null; } /** * Call IRadioVoice#acceptCall * @param serial Serial number of request * @throws RemoteException */ public void acceptCall(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.acceptCall(serial); } else { mRadioProxy.acceptCall(serial); } } /** * Call IRadioVoice#cancelPendingUssd * @param serial Serial number of request * @throws RemoteException */ public void cancelPendingUssd(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.cancelPendingUssd(serial); } else { mRadioProxy.cancelPendingUssd(serial); } } /** * Call IRadioVoice#conference * @param serial Serial number of request * @throws RemoteException */ public void conference(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.conference(serial); } else { mRadioProxy.conference(serial); } } /** * Call IRadioVoice#dial * @param serial Serial number of request * @param address Address * @param clirMode CLIR mode * @param uusInfo UUS info * @throws RemoteException */ public void dial(int serial, String address, int clirMode, UUSInfo uusInfo) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.dial(serial, RILUtils.convertToHalDialAidl(address, clirMode, uusInfo)); } else { mRadioProxy.dial(serial, RILUtils.convertToHalDial(address, clirMode, uusInfo)); } } /** * Call IRadioVoice#emergencyDial * @param serial Serial number of request * @param address Address * @param emergencyNumberInfo Emergency number information * @param hasKnownUserIntentEmergency Whether or not the request has known user intent emergency * @param clirMode CLIR mode * @param uusInfo UUS info * @throws RemoteException */ public void emergencyDial(int serial, String address, EmergencyNumber emergencyNumberInfo, boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.emergencyDial(serial, RILUtils.convertToHalDialAidl(address, clirMode, uusInfo), emergencyNumberInfo.getEmergencyServiceCategoryBitmaskInternalDial(), emergencyNumberInfo.getEmergencyUrns() != null ? emergencyNumberInfo.getEmergencyUrns().stream().toArray(String[]::new) : new String[0], emergencyNumberInfo.getEmergencyCallRouting(), hasKnownUserIntentEmergency, emergencyNumberInfo.getEmergencyNumberSourceBitmask() == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).emergencyDial_1_6(serial, RILUtils.convertToHalDial(address, clirMode, uusInfo), emergencyNumberInfo.getEmergencyServiceCategoryBitmaskInternalDial(), emergencyNumberInfo.getEmergencyUrns() != null ? new ArrayList(emergencyNumberInfo.getEmergencyUrns()) : new ArrayList<>(), emergencyNumberInfo.getEmergencyCallRouting(), hasKnownUserIntentEmergency, emergencyNumberInfo.getEmergencyNumberSourceBitmask() == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } else { mRadioProxy.emergencyDial(serial, RILUtils.convertToHalDial(address, clirMode, uusInfo), emergencyNumberInfo.getEmergencyServiceCategoryBitmaskInternalDial(), emergencyNumberInfo.getEmergencyUrns() != null ? new ArrayList(emergencyNumberInfo.getEmergencyUrns()) : new ArrayList<>(), emergencyNumberInfo.getEmergencyCallRouting(), hasKnownUserIntentEmergency, emergencyNumberInfo.getEmergencyNumberSourceBitmask() == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } } /** * Call IRadioVoice#exitEmergencyCallbackMode * @param serial Serial number of request * @throws RemoteException */ public void exitEmergencyCallbackMode(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.exitEmergencyCallbackMode(serial); } else { mRadioProxy.exitEmergencyCallbackMode(serial); } } /** * Call IRadioVoice#explicitCallTransfer * @param serial Serial number of request * @throws RemoteException */ public void explicitCallTransfer(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.explicitCallTransfer(serial); } else { mRadioProxy.explicitCallTransfer(serial); } } /** * Call IRadioVoice#getCallForwardStatus * @param serial Serial number of request * @param cfReason One of CF_REASON_* * @param serviceClass Sum of SERVICE_CLASS_* * @param number Number * @throws RemoteException */ public void getCallForwardStatus(int serial, int cfReason, int serviceClass, String number) throws RemoteException { if (isEmpty()) return; if (isAidl()) { android.hardware.radio.voice.CallForwardInfo cfInfo = new android.hardware.radio.voice.CallForwardInfo(); cfInfo.reason = cfReason; cfInfo.serviceClass = serviceClass; cfInfo.toa = PhoneNumberUtils.toaFromString(number); cfInfo.number = RILUtils.convertNullToEmptyString(number); cfInfo.timeSeconds = 0; mVoiceProxy.getCallForwardStatus(serial, cfInfo); } else { android.hardware.radio.V1_0.CallForwardInfo cfInfo = new android.hardware.radio.V1_0.CallForwardInfo(); cfInfo.reason = cfReason; cfInfo.serviceClass = serviceClass; cfInfo.toa = PhoneNumberUtils.toaFromString(number); cfInfo.number = RILUtils.convertNullToEmptyString(number); cfInfo.timeSeconds = 0; mRadioProxy.getCallForwardStatus(serial, cfInfo); } } /** * Call IRadioVoice#getCallWaiting * @param serial Serial number of request * @param serviceClass Sum of SERVICE_CLASS_* * @throws RemoteException */ public void getCallWaiting(int serial, int serviceClass) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getCallWaiting(serial, serviceClass); } else { mRadioProxy.getCallWaiting(serial, serviceClass); } } /** * Call IRadioVoice#getClip * @param serial Serial number of request * @throws RemoteException */ public void getClip(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getClip(serial); } else { mRadioProxy.getClip(serial); } } /** * Call IRadioVoice#getClir * @param serial Serial number of request * @throws RemoteException */ public void getClir(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getClir(serial); } else { mRadioProxy.getClir(serial); } } /** * Call IRadioVoice#getCurrentCalls * @param serial Serial number of request * @throws RemoteException */ public void getCurrentCalls(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getCurrentCalls(serial); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getCurrentCalls_1_6(serial); } else { mRadioProxy.getCurrentCalls(serial); } } /** * Call IRadioVoice#getLastCallFailCause * @param serial Serial number of request * @throws RemoteException */ public void getLastCallFailCause(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getLastCallFailCause(serial); } else { mRadioProxy.getLastCallFailCause(serial); } } /** * Call IRadioVoice#getMute * @param serial Serial number of request * @throws RemoteException */ public void getMute(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getMute(serial); } else { mRadioProxy.getMute(serial); } } /** * Call IRadioVoice#getPreferredVoicePrivacy * @param serial Serial number of request * @throws RemoteException */ public void getPreferredVoicePrivacy(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getPreferredVoicePrivacy(serial); } else { mRadioProxy.getPreferredVoicePrivacy(serial); } } /** * Call IRadioVoice#getTtyMode * @param serial Serial number of request * @throws RemoteException */ public void getTtyMode(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.getTtyMode(serial); } else { mRadioProxy.getTTYMode(serial); } } /** * Call IRadioVoice#handleStkCallSetupRequestFromSim * @param serial Serial number of request * @param accept Whether or not the call is to be accepted * @throws RemoteException */ public void handleStkCallSetupRequestFromSim(int serial, boolean accept) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.handleStkCallSetupRequestFromSim(serial, accept); } else { mRadioProxy.handleStkCallSetupRequestFromSim(serial, accept); } } /** * Call IRadioVoice#hangup * @param serial Serial number of request * @param gsmIndex Connection index * @throws RemoteException */ public void hangup(int serial, int gsmIndex) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.hangup(serial, gsmIndex); } else { mRadioProxy.hangup(serial, gsmIndex); } } /** * Call IRadioVoice#hangupForegroundResumeBackground * @param serial Serial number of request * @throws RemoteException */ public void hangupForegroundResumeBackground(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.hangupForegroundResumeBackground(serial); } else { mRadioProxy.hangupForegroundResumeBackground(serial); } } /** * Call IRadioVoice#hangupWaitingOrBackground * @param serial Serial number of request * @throws RemoteException */ public void hangupWaitingOrBackground(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.hangupWaitingOrBackground(serial); } else { mRadioProxy.hangupWaitingOrBackground(serial); } } /** * Call IRadioVoice#isVoNrEnabled * @param serial Serial number of request * @throws RemoteException */ public void isVoNrEnabled(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.isVoNrEnabled(serial); } } /** * Call IRadioVoice#rejectCall * @param serial Serial number of request * @throws RemoteException */ public void rejectCall(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.rejectCall(serial); } else { mRadioProxy.rejectCall(serial); } } /** * Call IRadioVoice#responseAcknowledgement * @throws RemoteException */ @Override public void responseAcknowledgement() throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.responseAcknowledgement(); } else { mRadioProxy.responseAcknowledgement(); } } /** * Call IRadioVoice#sendBurstDtmf * @param serial Serial number of request * @param dtmf DTMF string * @param on DTMF ON length in milliseconds, or 0 to use default * @param off DTMF OFF length in milliseconds, or 0 to use default * @throws RemoteException */ public void sendBurstDtmf(int serial, String dtmf, int on, int off) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.sendBurstDtmf(serial, dtmf, on, off); } else { mRadioProxy.sendBurstDtmf(serial, dtmf, on, off); } } /** * Call IRadioVoice#sendCdmaFeatureCode * @param serial Serial number of request * @param featureCode String associated with FLASH command * @throws RemoteException */ public void sendCdmaFeatureCode(int serial, String featureCode) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.sendCdmaFeatureCode(serial, featureCode); } else { mRadioProxy.sendCDMAFeatureCode(serial, featureCode); } } /** * Call IRadioVoice#sendDtmf * @param serial Serial number of request * @param s String with single char having one of 12 values: 0-0, *, # * @throws RemoteException */ public void sendDtmf(int serial, String s) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.sendDtmf(serial, s); } else { mRadioProxy.sendDtmf(serial, s); } } /** * Call IRadioVoice#sendUssd * @param serial Serial number of request * @param ussd String containing the USSD request in UTF-8 format * @throws RemoteException */ public void sendUssd(int serial, String ussd) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.sendUssd(serial, ussd); } else { mRadioProxy.sendUssd(serial, ussd); } } /** * Call IRadioVoice#separateConnection * @param serial Serial number of request * @param gsmIndex Connection index * @throws RemoteException */ public void separateConnection(int serial, int gsmIndex) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.separateConnection(serial, gsmIndex); } else { mRadioProxy.separateConnection(serial, gsmIndex); } } /** * Call IRadioVoice#setCallForward * @param serial Serial number of request * @param action One of CF_ACTION_* * @param cfReason One of CF_REASON_* * @param serviceClass Sum of SERVICE_CLASSS_* * @param number Number * @param timeSeconds Time in seconds * @throws RemoteException */ public void setCallForward(int serial, int action, int cfReason, int serviceClass, String number, int timeSeconds) throws RemoteException { if (isEmpty()) return; if (isAidl()) { android.hardware.radio.voice.CallForwardInfo cfInfo = new android.hardware.radio.voice.CallForwardInfo(); cfInfo.status = action; cfInfo.reason = cfReason; cfInfo.serviceClass = serviceClass; cfInfo.toa = PhoneNumberUtils.toaFromString(number); cfInfo.number = RILUtils.convertNullToEmptyString(number); cfInfo.timeSeconds = timeSeconds; mVoiceProxy.setCallForward(serial, cfInfo); } else { android.hardware.radio.V1_0.CallForwardInfo cfInfo = new android.hardware.radio.V1_0.CallForwardInfo(); cfInfo.status = action; cfInfo.reason = cfReason; cfInfo.serviceClass = serviceClass; cfInfo.toa = PhoneNumberUtils.toaFromString(number); cfInfo.number = RILUtils.convertNullToEmptyString(number); cfInfo.timeSeconds = timeSeconds; mRadioProxy.setCallForward(serial, cfInfo); } } /** * Call IRadioVoice#setCallWaiting * @param serial Serial number of request * @param enable True to enable, false to disable * @param serviceClass Sum of SERVICE_CLASS_* * @throws RemoteException */ public void setCallWaiting(int serial, boolean enable, int serviceClass) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setCallWaiting(serial, enable, serviceClass); } else { mRadioProxy.setCallWaiting(serial, enable, serviceClass); } } /** * Call IRadioVoice#setClir * @param serial Serial number of request * @param status One of CLIR_* * @throws RemoteException */ public void setClir(int serial, int status) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setClir(serial, status); } else { mRadioProxy.setClir(serial, status); } } /** * Call IRadioVoice#setMute * @param serial Serial number of request * @param enable True to enable, false to disable * @throws RemoteException */ public void setMute(int serial, boolean enable) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setMute(serial, enable); } else { mRadioProxy.setMute(serial, enable); } } /** * Call IRadioVoice#setPreferredVoicePrivacy * @param serial Serial number of request * @param enable True is enhanced, false is normal voice privacy * @throws RemoteException */ public void setPreferredVoicePrivacy(int serial, boolean enable) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setPreferredVoicePrivacy(serial, enable); } else { mRadioProxy.setPreferredVoicePrivacy(serial, enable); } } /** * Call IRadioVoice#setTtyMode * @param serial Serial number of request * @param mode One of TTY_MODE_* * @throws RemoteException */ public void setTtyMode(int serial, int mode) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setTtyMode(serial, mode); } else { mRadioProxy.setTTYMode(serial, mode); } } /** * Call IRadioVoice#setVoNrEnabled * @param serial Serial number of request * @param enable True to enable, false to disable * @throws RemoteException */ public void setVoNrEnabled(int serial, boolean enable) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.setVoNrEnabled(serial, enable); } } /** * Call IRadioVoice#startDtmf * @param serial Serial number of request * @param s String having a single character with one of 12 values: 0-9, *, # * @throws RemoteException */ public void startDtmf(int serial, String s) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.startDtmf(serial, s); } else { mRadioProxy.startDtmf(serial, s); } } /** * Call IRadioVoice#stopDtmf * @param serial Serial number of request * @throws RemoteException */ public void stopDtmf(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.stopDtmf(serial); } else { mRadioProxy.stopDtmf(serial); } } /** * Call IRadioVoice#switchWaitingOrHoldingAndActive * @param serial Serial number of request * @throws RemoteException */ public void switchWaitingOrHoldingAndActive(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mVoiceProxy.switchWaitingOrHoldingAndActive(serial); } else { mRadioProxy.switchWaitingOrHoldingAndActive(serial); } } }