678 lines
25 KiB
Java
678 lines
25 KiB
Java
/*
|
|
* Copyright (C) 2018 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 static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_NSA;
|
|
import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_SA;
|
|
|
|
import static com.android.internal.telephony.RILConstants.RADIO_NOT_AVAILABLE;
|
|
import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIMULTANEOUS_CALLING_SUPPORT;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM;
|
|
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG;
|
|
|
|
import android.content.Context;
|
|
import android.os.AsyncResult;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.Message;
|
|
import android.os.Registrant;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceManager;
|
|
import android.os.Trace;
|
|
import android.os.WorkSource;
|
|
import android.telephony.TelephonyManager;
|
|
import android.telephony.UiccSlotMapping;
|
|
import android.util.SparseArray;
|
|
|
|
import com.android.telephony.Rlog;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
/**
|
|
* This class provides wrapper APIs for IRadioConfig interface.
|
|
*/
|
|
public class RadioConfig extends Handler {
|
|
private static final String TAG = "RadioConfig";
|
|
private static final boolean DBG = true;
|
|
private static final boolean VDBG = false; //STOPSHIP if true
|
|
private static final Object sLock = new Object();
|
|
|
|
static final int EVENT_HIDL_SERVICE_DEAD = 1;
|
|
static final int EVENT_AIDL_SERVICE_DEAD = 2;
|
|
|
|
private final boolean mIsMobileNetworkSupported;
|
|
private final SparseArray<RILRequest> mRequestList = new SparseArray<>();
|
|
/* default work source which will blame phone process */
|
|
private final WorkSource mDefaultWorkSource;
|
|
private final int[] mDeviceNrCapabilities;
|
|
private final AtomicLong mRadioConfigProxyCookie = new AtomicLong(0);
|
|
private final RadioConfigProxy mRadioConfigProxy;
|
|
private MockModem mMockModem;
|
|
private static Context sContext;
|
|
|
|
private static RadioConfig sRadioConfig;
|
|
|
|
protected Registrant mSimSlotStatusRegistrant;
|
|
|
|
protected Registrant mSimultaneousCallingSupportStatusRegistrant;
|
|
|
|
private boolean isMobileDataCapable(Context context) {
|
|
final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
|
|
return tm != null && tm.isDataCapable();
|
|
}
|
|
|
|
private RadioConfig(Context context, HalVersion radioHalVersion) {
|
|
mIsMobileNetworkSupported = isMobileDataCapable(context);
|
|
mRadioConfigProxy = new RadioConfigProxy(this, radioHalVersion);
|
|
mDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid,
|
|
context.getPackageName());
|
|
|
|
boolean is5gStandalone = context.getResources().getBoolean(
|
|
com.android.internal.R.bool.config_telephony5gStandalone);
|
|
boolean is5gNonStandalone = context.getResources().getBoolean(
|
|
com.android.internal.R.bool.config_telephony5gNonStandalone);
|
|
|
|
if (!is5gStandalone && !is5gNonStandalone) {
|
|
mDeviceNrCapabilities = new int[0];
|
|
} else {
|
|
List<Integer> list = new ArrayList<>();
|
|
if (is5gNonStandalone) {
|
|
list.add(DEVICE_NR_CAPABILITY_NSA);
|
|
}
|
|
if (is5gStandalone) {
|
|
list.add(DEVICE_NR_CAPABILITY_SA);
|
|
}
|
|
mDeviceNrCapabilities = list.stream().mapToInt(Integer::valueOf).toArray();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the singleton static instance of RadioConfig
|
|
*/
|
|
public static RadioConfig getInstance() {
|
|
synchronized (sLock) {
|
|
if (sRadioConfig == null) {
|
|
throw new RuntimeException(
|
|
"RadioConfig.getInstance can't be called before make()");
|
|
}
|
|
return sRadioConfig;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes the radio config based on the context and the radio hal version passed in
|
|
*/
|
|
public static RadioConfig make(Context c, HalVersion radioHalVersion) {
|
|
synchronized (sLock) {
|
|
if (sRadioConfig != null) {
|
|
throw new RuntimeException("RadioConfig.make() should only be called once");
|
|
}
|
|
sContext = c;
|
|
sRadioConfig = new RadioConfig(c, radioHalVersion);
|
|
return sRadioConfig;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void handleMessage(Message message) {
|
|
if (message.what == EVENT_HIDL_SERVICE_DEAD) {
|
|
logd("handleMessage: EVENT_HIDL_SERVICE_DEAD cookie = " + message.obj
|
|
+ " mRadioConfigProxyCookie = " + mRadioConfigProxyCookie.get());
|
|
if ((long) message.obj == mRadioConfigProxyCookie.get()) {
|
|
resetProxyAndRequestList("EVENT_HIDL_SERVICE_DEAD", null);
|
|
}
|
|
} else if (message.what == EVENT_AIDL_SERVICE_DEAD) {
|
|
logd("handleMessage: EVENT_AIDL_SERVICE_DEAD mRadioConfigProxyCookie = "
|
|
+ mRadioConfigProxyCookie.get());
|
|
resetProxyAndRequestList("EVENT_AIDL_SERVICE_DEAD", null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Release each request in mRequestList then clear the list
|
|
* @param error is the RIL_Errno sent back
|
|
* @param loggable true means to print all requests in mRequestList
|
|
*/
|
|
private void clearRequestList(int error, boolean loggable) {
|
|
RILRequest rr;
|
|
synchronized (mRequestList) {
|
|
int count = mRequestList.size();
|
|
if (DBG && loggable) {
|
|
logd("clearRequestList: mRequestList=" + count);
|
|
}
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
rr = mRequestList.valueAt(i);
|
|
if (DBG && loggable) {
|
|
logd(i + ": [" + rr.mSerial + "] " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
rr.onError(error, null);
|
|
rr.release();
|
|
}
|
|
mRequestList.clear();
|
|
}
|
|
}
|
|
|
|
private void resetProxyAndRequestList(String caller, Exception e) {
|
|
loge(caller + ": " + e);
|
|
mRadioConfigProxy.clear();
|
|
|
|
// increment the cookie so that death notification can be ignored
|
|
mRadioConfigProxyCookie.incrementAndGet();
|
|
|
|
RILRequest.resetSerial();
|
|
// Clear request list on close
|
|
clearRequestList(RADIO_NOT_AVAILABLE, false);
|
|
|
|
getRadioConfigProxy(null);
|
|
}
|
|
|
|
/**
|
|
* Returns a holder that has either:
|
|
* - getV1() -> {@link android.hardware.radio.config.V1_0.IRadioConfig}
|
|
* - getV2() -> {@link android.hardware.radio.config.IRadioConfig}
|
|
* that returns corresponding hal implementation
|
|
*/
|
|
public RadioConfigProxy getRadioConfigProxy(Message result) {
|
|
if (!mIsMobileNetworkSupported) {
|
|
if (VDBG) logd("getRadioConfigProxy: Not calling getService(): wifi-only");
|
|
if (result != null) {
|
|
AsyncResult.forMessage(result, null,
|
|
CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
|
|
result.sendToTarget();
|
|
}
|
|
mRadioConfigProxy.clear();
|
|
return mRadioConfigProxy;
|
|
}
|
|
|
|
if (!mRadioConfigProxy.isEmpty()) {
|
|
return mRadioConfigProxy;
|
|
}
|
|
|
|
updateRadioConfigProxy();
|
|
|
|
if (mRadioConfigProxy.isEmpty() && result != null) {
|
|
AsyncResult.forMessage(
|
|
result, null, CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
|
|
result.sendToTarget();
|
|
}
|
|
|
|
return mRadioConfigProxy;
|
|
}
|
|
|
|
/**
|
|
* Request to enable/disable the mock modem service.
|
|
* This is invoked from shell commands during CTS testing only.
|
|
*
|
|
* @param serviceName the service name we want to bind to
|
|
*/
|
|
public boolean setModemService(String serviceName) {
|
|
boolean serviceBound = true;
|
|
|
|
if (serviceName != null) {
|
|
logd("Overriding connected service to MockModemService");
|
|
mMockModem = null;
|
|
|
|
mMockModem = new MockModem(sContext, serviceName);
|
|
if (mMockModem == null) {
|
|
loge("MockModem creation failed.");
|
|
return false;
|
|
}
|
|
|
|
mMockModem.bindToMockModemService(MockModem.RADIOCONFIG_SERVICE);
|
|
|
|
int retryCount = 0;
|
|
IBinder binder;
|
|
do {
|
|
binder = mMockModem.getServiceBinder(MockModem.RADIOCONFIG_SERVICE);
|
|
|
|
retryCount++;
|
|
if (binder == null) {
|
|
logd("Retry(" + retryCount + ") Mock RadioConfig");
|
|
try {
|
|
Thread.sleep(MockModem.BINDER_RETRY_MILLIS);
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
} while ((binder == null) && (retryCount < MockModem.BINDER_MAX_RETRY));
|
|
|
|
if (binder == null) {
|
|
loge("Mock RadioConfig bind fail");
|
|
serviceBound = false;
|
|
}
|
|
|
|
if (serviceBound) resetProxyAndRequestList("EVENT_HIDL_SERVICE_DEAD", null);
|
|
}
|
|
|
|
if ((serviceName == null) || (!serviceBound)) {
|
|
if (serviceBound) logd("Unbinding to mock RadioConfig service");
|
|
|
|
if (mMockModem != null) {
|
|
mMockModem = null;
|
|
resetProxyAndRequestList("EVENT_AIDL_SERVICE_DEAD", null);
|
|
}
|
|
}
|
|
|
|
return serviceBound;
|
|
}
|
|
|
|
private void updateRadioConfigProxy() {
|
|
IBinder service;
|
|
if (mMockModem == null) {
|
|
service = ServiceManager.waitForDeclaredService(
|
|
android.hardware.radio.config.IRadioConfig.DESCRIPTOR + "/default");
|
|
} else {
|
|
// Binds to Mock RadioConfig Service
|
|
service = mMockModem.getServiceBinder(MockModem.RADIOCONFIG_SERVICE);
|
|
}
|
|
|
|
if (service != null) {
|
|
mRadioConfigProxy.setAidl(
|
|
android.hardware.radio.config.IRadioConfig.Stub.asInterface(service));
|
|
}
|
|
|
|
if (mRadioConfigProxy.isEmpty()) {
|
|
try {
|
|
mRadioConfigProxy.setHidl(RIL.RADIO_HAL_VERSION_1_3,
|
|
android.hardware.radio.config.V1_3.IRadioConfig.getService(true));
|
|
} catch (RemoteException | NoSuchElementException e) {
|
|
mRadioConfigProxy.clear();
|
|
loge("getHidlRadioConfigProxy1_3: RadioConfigProxy getService: " + e);
|
|
}
|
|
}
|
|
|
|
if (mRadioConfigProxy.isEmpty()) {
|
|
try {
|
|
mRadioConfigProxy.setHidl(RIL.RADIO_HAL_VERSION_1_1,
|
|
android.hardware.radio.config.V1_1.IRadioConfig.getService(true));
|
|
} catch (RemoteException | NoSuchElementException e) {
|
|
mRadioConfigProxy.clear();
|
|
loge("getHidlRadioConfigProxy1_1: RadioConfigProxy getService | linkToDeath: " + e);
|
|
}
|
|
}
|
|
|
|
if (mRadioConfigProxy.isEmpty()) {
|
|
loge("IRadioConfig <1.1 is no longer supported.");
|
|
}
|
|
|
|
if (!mRadioConfigProxy.isEmpty()) {
|
|
try {
|
|
mRadioConfigProxy.linkToDeath(mRadioConfigProxyCookie.incrementAndGet());
|
|
mRadioConfigProxy.setResponseFunctions(this);
|
|
return;
|
|
} catch (RemoteException e) {
|
|
mRadioConfigProxy.clear();
|
|
loge("RadioConfigProxy: failed to linkToDeath() or setResponseFunction()");
|
|
}
|
|
}
|
|
|
|
loge("getRadioConfigProxy: mRadioConfigProxy == null");
|
|
}
|
|
|
|
private RILRequest obtainRequest(int request, Message result, WorkSource workSource) {
|
|
RILRequest rr = RILRequest.obtain(request, result, workSource);
|
|
Trace.asyncTraceForTrackBegin(
|
|
Trace.TRACE_TAG_NETWORK, "RIL", RILUtils.requestToString(rr.mRequest), rr.mSerial);
|
|
|
|
synchronized (mRequestList) {
|
|
mRequestList.append(rr.mSerial, rr);
|
|
}
|
|
return rr;
|
|
}
|
|
|
|
private RILRequest findAndRemoveRequestFromList(int serial) {
|
|
RILRequest rr;
|
|
synchronized (mRequestList) {
|
|
rr = mRequestList.get(serial);
|
|
|
|
if (rr != null) {
|
|
Trace.asyncTraceForTrackEnd(
|
|
Trace.TRACE_TAG_NETWORK, "RIL", rr.mSerial);
|
|
mRequestList.remove(serial);
|
|
}
|
|
}
|
|
|
|
return rr;
|
|
}
|
|
|
|
/**
|
|
* This is a helper function to be called when a RadioConfigResponse callback is called.
|
|
* It finds and returns RILRequest corresponding to the response if one is found.
|
|
* @param responseInfo RadioResponseInfo received in response callback
|
|
* @return RILRequest corresponding to the response
|
|
*/
|
|
public RILRequest processResponse(android.hardware.radio.RadioResponseInfo responseInfo) {
|
|
int serial = responseInfo.serial;
|
|
int error = responseInfo.error;
|
|
int type = responseInfo.type;
|
|
|
|
if (type != android.hardware.radio.RadioResponseType.SOLICITED) {
|
|
loge("processResponse: Unexpected response type " + type);
|
|
}
|
|
|
|
RILRequest rr = findAndRemoveRequestFromList(serial);
|
|
if (rr == null) {
|
|
loge("processResponse: Unexpected response! serial: " + serial + " error: " + error);
|
|
return null;
|
|
}
|
|
|
|
return rr;
|
|
}
|
|
|
|
/**
|
|
* This is a helper function to be called when a RadioConfigResponse callback is called.
|
|
* It finds and returns RILRequest corresponding to the response if one is found.
|
|
* @param responseInfo RadioResponseInfo received in response callback
|
|
* @return RILRequest corresponding to the response
|
|
*/
|
|
public RILRequest processResponse(android.hardware.radio.V1_0.RadioResponseInfo responseInfo) {
|
|
int serial = responseInfo.serial;
|
|
int error = responseInfo.error;
|
|
int type = responseInfo.type;
|
|
|
|
if (type != android.hardware.radio.RadioResponseType.SOLICITED) {
|
|
loge("processResponse: Unexpected response type " + type);
|
|
}
|
|
|
|
RILRequest rr = findAndRemoveRequestFromList(serial);
|
|
if (rr == null) {
|
|
loge("processResponse: Unexpected response! serial: " + serial + " error: " + error);
|
|
return null;
|
|
}
|
|
|
|
return rr;
|
|
}
|
|
|
|
/**
|
|
* This is a helper function to be called when a RadioConfigResponse callback is called.
|
|
* It finds and returns RILRequest corresponding to the response if one is found.
|
|
* @param responseInfo RadioResponseInfo received in response callback
|
|
* @return RILRequest corresponding to the response
|
|
*/
|
|
public RILRequest processResponse_1_6(
|
|
android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
|
|
int serial = responseInfo.serial;
|
|
int error = responseInfo.error;
|
|
int type = responseInfo.type;
|
|
if (type != android.hardware.radio.RadioResponseType.SOLICITED) {
|
|
loge("processResponse: Unexpected response type " + type);
|
|
}
|
|
|
|
RILRequest rr = findAndRemoveRequestFromList(serial);
|
|
if (rr == null) {
|
|
loge("processResponse: Unexpected response! serial: " + serial + " error: " + error);
|
|
return null;
|
|
}
|
|
|
|
return rr;
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for IRadioConfig.getSimSlotsStatus().
|
|
*/
|
|
public void getSimSlotsStatus(Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(result);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLOT_STATUS, result, mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
try {
|
|
proxy.getSimSlotStatus(rr.mSerial);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("getSimSlotsStatus", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for IRadioConfig.setPreferredDataModem(int modemId).
|
|
*/
|
|
public void setPreferredDataModem(int modemId, Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(null);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
if (!isSetPreferredDataCommandSupported()) {
|
|
if (result != null) {
|
|
AsyncResult.forMessage(result, null,
|
|
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
|
|
result.sendToTarget();
|
|
}
|
|
return;
|
|
}
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_DATA_MODEM,
|
|
result, mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
try {
|
|
proxy.setPreferredDataModem(rr.mSerial, modemId);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("setPreferredDataModem", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for IRadioConfig.getSimultaneousCallingSupport().
|
|
*/
|
|
public void updateSimultaneousCallingSupport(Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(null);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_2_2)) {
|
|
if (result != null) {
|
|
AsyncResult.forMessage(result, null,
|
|
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
|
|
result.sendToTarget();
|
|
}
|
|
return;
|
|
}
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIMULTANEOUS_CALLING_SUPPORT, result,
|
|
mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
try {
|
|
proxy.updateSimultaneousCallingSupport(rr.mSerial);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("updateSimultaneousCallingSupport", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for IRadioConfig.getPhoneCapability().
|
|
*/
|
|
public void getPhoneCapability(Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(null);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_1)) {
|
|
if (result != null) {
|
|
AsyncResult.forMessage(result, null,
|
|
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
|
|
result.sendToTarget();
|
|
}
|
|
return;
|
|
}
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_GET_PHONE_CAPABILITY, result, mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
try {
|
|
proxy.getPhoneCapability(rr.mSerial);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("getPhoneCapability", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return whether current radio config version supports SET_PREFERRED_DATA_MODEM command.
|
|
* If yes, we'll use RIL_REQUEST_SET_PREFERRED_DATA_MODEM to indicate which modem is preferred.
|
|
* If not, we shall use RIL_REQUEST_ALLOW_DATA for on-demand PS attach / detach.
|
|
* See PhoneSwitcher for more details.
|
|
*/
|
|
public boolean isSetPreferredDataCommandSupported() {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(null);
|
|
return !proxy.isEmpty() && proxy.getVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_1);
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for IRadioConfig.setSimSlotsMapping(int32_t serial, vec<uint32_t> slotMap).
|
|
*/
|
|
public void setSimSlotsMapping(List<UiccSlotMapping> slotMapping, Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(result);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING, result,
|
|
mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " "
|
|
+ slotMapping);
|
|
}
|
|
try {
|
|
proxy.setSimSlotsMapping(rr.mSerial, slotMapping);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("setSimSlotsMapping", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrapper function for using IRadioConfig.setNumOfLiveModems(int32_t serial,
|
|
* byte numOfLiveModems) to switch between single-sim and multi-sim.
|
|
*/
|
|
public void setNumOfLiveModems(int numOfLiveModems, Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(result);
|
|
if (proxy.isEmpty()) return;
|
|
|
|
if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_1)) {
|
|
if (result != null) {
|
|
AsyncResult.forMessage(
|
|
result, null, CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
|
|
result.sendToTarget();
|
|
}
|
|
return;
|
|
}
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG,
|
|
result, mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)
|
|
+ ", numOfLiveModems = " + numOfLiveModems);
|
|
}
|
|
try {
|
|
proxy.setNumOfLiveModems(rr.mSerial, numOfLiveModems);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("setNumOfLiveModems", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register a handler to get SIM slots that support simultaneous calling changed notifications.
|
|
*/
|
|
public void registerForSimultaneousCallingSupportStatusChanged(Handler h, int what,
|
|
Object obj) {
|
|
mSimultaneousCallingSupportStatusRegistrant = new Registrant(h, what, obj);
|
|
}
|
|
|
|
/**
|
|
* Register a handler to get SIM slot status changed notifications.
|
|
*/
|
|
public void registerForSimSlotStatusChanged(Handler h, int what, Object obj) {
|
|
mSimSlotStatusRegistrant = new Registrant(h, what, obj);
|
|
}
|
|
|
|
/**
|
|
* Unregister corresponding to registerForSimSlotStatusChanged().
|
|
*/
|
|
public void unregisterForSimSlotStatusChanged(Handler h) {
|
|
if (mSimSlotStatusRegistrant != null && mSimSlotStatusRegistrant.getHandler() == h) {
|
|
mSimSlotStatusRegistrant.clear();
|
|
mSimSlotStatusRegistrant = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the hal capabilities from the device.
|
|
*/
|
|
public void getHalDeviceCapabilities(Message result) {
|
|
RadioConfigProxy proxy = getRadioConfigProxy(Message.obtain(result));
|
|
if (proxy.isEmpty()) return;
|
|
|
|
if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_3)) {
|
|
if (result != null) {
|
|
if (DBG) {
|
|
logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED");
|
|
}
|
|
AsyncResult.forMessage(result,
|
|
/* Send response such that all capabilities are supported (depending on
|
|
the hal version of course.) */
|
|
proxy.getFullCapabilitySet(),
|
|
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
|
|
result.sendToTarget();
|
|
} else {
|
|
if (DBG) {
|
|
logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED "
|
|
+ "on complete message not set.");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
RILRequest rr = obtainRequest(RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES,
|
|
result, mDefaultWorkSource);
|
|
if (DBG) {
|
|
logd(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
|
|
}
|
|
try {
|
|
proxy.getHalDeviceCapabilities(rr.mSerial);
|
|
} catch (RemoteException | RuntimeException e) {
|
|
resetProxyAndRequestList("getHalDeviceCapabilities", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the device's nr capability.
|
|
*/
|
|
public int[] getDeviceNrCapabilities() {
|
|
return mDeviceNrCapabilities;
|
|
}
|
|
|
|
private static void logd(String log) {
|
|
Rlog.d(TAG, log);
|
|
}
|
|
|
|
private static void loge(String log) {
|
|
Rlog.e(TAG, log);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "RadioConfig[" + "mRadioConfigProxy=" + mRadioConfigProxy + ']';
|
|
}
|
|
}
|