(ImsService API changes for Better IMS Threading) ImsService to execute binder calls in Executor.
In order to avoid undefined behavior when the framework calls a method through IPC, the ImsService will now be able to define an Executor that the ImsService can be used to execute the methods By default all ImsService level method calls will use this Executor. Sub-classes will also use this Executor unless specified via constuctor which takes executor as an argument. Test: atest CtsTelephonyTestCases:ImsCallingTest Bug: 171037053 Merged-In: I10621f9a767ba5bc55373f49caf426e66adbec77 Change-Id: I10621f9a767ba5bc55373f49caf426e66adbec77
This commit is contained in:
@@ -12926,6 +12926,7 @@ package android.telephony.ims {
|
||||
method public void disableIms(int);
|
||||
method public void enableIms(int);
|
||||
method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
|
||||
method @NonNull public java.util.concurrent.Executor getExecutor();
|
||||
method public long getImsServiceCapabilities();
|
||||
method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
|
||||
method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
|
||||
@@ -13546,6 +13547,7 @@ package android.telephony.ims.feature {
|
||||
|
||||
public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
|
||||
ctor public MmTelFeature();
|
||||
ctor public MmTelFeature(@NonNull java.util.concurrent.Executor);
|
||||
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
|
||||
method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
|
||||
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
|
||||
@@ -13579,7 +13581,7 @@ package android.telephony.ims.feature {
|
||||
}
|
||||
|
||||
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
|
||||
ctor @Deprecated public RcsFeature();
|
||||
ctor public RcsFeature();
|
||||
ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
|
||||
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
|
||||
method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
|
||||
@@ -13684,6 +13686,7 @@ package android.telephony.ims.stub {
|
||||
}
|
||||
|
||||
public class ImsConfigImplBase {
|
||||
ctor public ImsConfigImplBase(@NonNull java.util.concurrent.Executor);
|
||||
ctor public ImsConfigImplBase();
|
||||
method public int getConfigInt(int);
|
||||
method public String getConfigString(int);
|
||||
@@ -13736,6 +13739,7 @@ package android.telephony.ims.stub {
|
||||
|
||||
public class ImsRegistrationImplBase {
|
||||
ctor public ImsRegistrationImplBase();
|
||||
ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor);
|
||||
method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
|
||||
method public final void onRegistered(int);
|
||||
method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
|
||||
@@ -13848,6 +13852,7 @@ package android.telephony.ims.stub {
|
||||
}
|
||||
|
||||
public class SipTransportImplBase {
|
||||
ctor public SipTransportImplBase();
|
||||
ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
|
||||
method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback);
|
||||
method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.telephony.ims;
|
||||
|
||||
import android.annotation.LongDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
@@ -44,11 +45,18 @@ import android.util.SparseArray;
|
||||
|
||||
import com.android.ims.internal.IImsFeatureStatusCallback;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
|
||||
@@ -173,7 +181,21 @@ public class ImsService extends Service {
|
||||
private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
|
||||
|
||||
private IImsServiceControllerListener mListener;
|
||||
private Executor mExecutor;
|
||||
|
||||
/**
|
||||
* Create a new ImsService.
|
||||
* <p>
|
||||
* Method stubs called from the framework will be called asynchronously. Vendor specifies the
|
||||
* {@link Executor} that the methods stubs will be called. If mExecutor is set to null by
|
||||
* vendor use Runnable::run.
|
||||
*/
|
||||
public ImsService() {
|
||||
mExecutor = ImsService.this.getExecutor();
|
||||
if (mExecutor == null) {
|
||||
mExecutor = Runnable::run;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener that notifies the framework of ImsService changes.
|
||||
@@ -201,78 +223,132 @@ public class ImsService extends Service {
|
||||
|
||||
@Override
|
||||
public IImsMmTelFeature createMmTelFeature(int slotId) {
|
||||
return createMmTelFeatureInternal(slotId);
|
||||
return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
|
||||
"createMmTelFeature");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsRcsFeature createRcsFeature(int slotId) {
|
||||
return createRcsFeatureInternal(slotId);
|
||||
return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
|
||||
"createRcsFeature");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFeatureStatusCallback(int slotId, int featureType,
|
||||
IImsFeatureStatusCallback c) {
|
||||
ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
|
||||
executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback(
|
||||
slotId, featureType, c), "addFeatureStatusCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFeatureStatusCallback(int slotId, int featureType,
|
||||
IImsFeatureStatusCallback c) {
|
||||
ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
|
||||
executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback(
|
||||
slotId, featureType, c), "removeFeatureStatusCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeImsFeature(int slotId, int featureType) {
|
||||
ImsService.this.removeImsFeature(slotId, featureType);
|
||||
executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
|
||||
"removeImsFeature");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImsFeatureConfiguration querySupportedImsFeatures() {
|
||||
return ImsService.this.querySupportedImsFeatures();
|
||||
return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(),
|
||||
"ImsFeatureConfiguration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getImsServiceCapabilities() {
|
||||
long caps = ImsService.this.getImsServiceCapabilities();
|
||||
long sanitizedCaps = sanitizeCapabilities(caps);
|
||||
if (caps != sanitizedCaps) {
|
||||
Log.w(LOG_TAG, "removing invalid bits from field: 0x"
|
||||
+ Long.toHexString(caps ^ sanitizedCaps));
|
||||
}
|
||||
return sanitizedCaps;
|
||||
return executeMethodAsyncForResult(() -> {
|
||||
long caps = ImsService.this.getImsServiceCapabilities();
|
||||
long sanitizedCaps = sanitizeCapabilities(caps);
|
||||
if (caps != sanitizedCaps) {
|
||||
Log.w(LOG_TAG, "removing invalid bits from field: 0x"
|
||||
+ Long.toHexString(caps ^ sanitizedCaps));
|
||||
}
|
||||
return sanitizedCaps;
|
||||
}, "getImsServiceCapabilities");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyImsServiceReadyForFeatureCreation() {
|
||||
ImsService.this.readyForFeatureCreation();
|
||||
executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(),
|
||||
"notifyImsServiceReadyForFeatureCreation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsConfig getConfig(int slotId) {
|
||||
ImsConfigImplBase c = ImsService.this.getConfig(slotId);
|
||||
return c != null ? c.getIImsConfig() : null;
|
||||
return executeMethodAsyncForResult(() -> {
|
||||
ImsConfigImplBase c = ImsService.this.getConfig(slotId);
|
||||
if (c != null) {
|
||||
c.setDefaultExecutor(mExecutor);
|
||||
return c.getIImsConfig();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, "getConfig");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsRegistration getRegistration(int slotId) {
|
||||
ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
|
||||
return r != null ? r.getBinder() : null;
|
||||
return executeMethodAsyncForResult(() -> {
|
||||
ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
|
||||
if (r != null) {
|
||||
r.setDefaultExecutor(mExecutor);
|
||||
return r.getBinder();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, "getRegistration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISipTransport getSipTransport(int slotId) {
|
||||
SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
|
||||
return s != null ? s.getBinder() : null;
|
||||
return executeMethodAsyncForResult(() -> {
|
||||
SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
|
||||
if (s != null) {
|
||||
s.setDefaultExecutor(mExecutor);
|
||||
return s.getBinder();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}, "getSipTransport");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableIms(int slotId) {
|
||||
ImsService.this.enableIms(slotId);
|
||||
executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableIms(int slotId) {
|
||||
ImsService.this.disableIms(slotId);
|
||||
executeMethodAsync(() -> ImsService.this.disableIms(slotId), "disableIms");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -300,6 +376,7 @@ public class ImsService extends Service {
|
||||
MmTelFeature f = createMmTelFeature(slotId);
|
||||
if (f != null) {
|
||||
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
|
||||
f.setDefaultExecutor(mExecutor);
|
||||
return f.getBinder();
|
||||
} else {
|
||||
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
|
||||
@@ -310,6 +387,7 @@ public class ImsService extends Service {
|
||||
private IImsRcsFeature createRcsFeatureInternal(int slotId) {
|
||||
RcsFeature f = createRcsFeature(slotId);
|
||||
if (f != null) {
|
||||
f.setDefaultExecutor(mExecutor);
|
||||
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
|
||||
return f.getBinder();
|
||||
} else {
|
||||
@@ -562,4 +640,15 @@ public class ImsService extends Service {
|
||||
result.append("}");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The ImsService will now be able to define an Executor that the ImsService can be used to
|
||||
* execute the methods. By default all ImsService level method calls will use this Executor.
|
||||
* The ImsService has set the default executor as Runnable::run,
|
||||
* Should be override or default executor will be used.
|
||||
* @return an Executor used to execute methods called remotely by the framework.
|
||||
*/
|
||||
public @NonNull Executor getExecutor() {
|
||||
return Runnable::run;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,16 +40,25 @@ import android.telephony.ims.stub.ImsRegistrationImplBase;
|
||||
import android.telephony.ims.stub.ImsSmsImplBase;
|
||||
import android.telephony.ims.stub.ImsUtImplBase;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.ims.internal.IImsCallSession;
|
||||
import com.android.ims.internal.IImsEcbm;
|
||||
import com.android.ims.internal.IImsMultiEndpoint;
|
||||
import com.android.ims.internal.IImsUt;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support.
|
||||
@@ -60,6 +69,7 @@ import java.util.Set;
|
||||
public class MmTelFeature extends ImsFeature {
|
||||
|
||||
private static final String LOG_TAG = "MmTelFeature";
|
||||
private Executor mExecutor;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -68,160 +78,261 @@ public class MmTelFeature extends ImsFeature {
|
||||
public MmTelFeature() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MmTelFeature using the Executor specified for methods being called by the
|
||||
* framework.
|
||||
* @param executor The executor for the framework to use when executing the methods overridden
|
||||
* by the implementation of MmTelFeature.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public MmTelFeature(@NonNull Executor executor) {
|
||||
super();
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
|
||||
|
||||
@Override
|
||||
public void setListener(IImsMmTelListener l) {
|
||||
MmTelFeature.this.setListener(l);
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFeatureState() throws RemoteException {
|
||||
try {
|
||||
return MmTelFeature.this.getFeatureState();
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(),
|
||||
"getFeatureState");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ImsCallProfile createCallProfile(int callSessionType, int callType)
|
||||
throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
return MmTelFeature.this.createCallProfile(callSessionType, callType);
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile(
|
||||
callSessionType, callType), "createCallProfile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
|
||||
throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types));
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(
|
||||
new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
return createCallSessionInterface(profile);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
IImsCallSession result = executeMethodAsyncForResult(() -> {
|
||||
try {
|
||||
return createCallSessionInterface(profile);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return null;
|
||||
}
|
||||
}, "createCallSession");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int shouldProcessCall(String[] numbers) {
|
||||
synchronized (mLock) {
|
||||
return MmTelFeature.this.shouldProcessCall(numbers);
|
||||
Integer result = executeMethodAsyncForResultNoException(() ->
|
||||
MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall");
|
||||
if (result != null) {
|
||||
return result.intValue();
|
||||
} else {
|
||||
return PROCESS_CALL_CSFB;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsUt getUtInterface() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
return MmTelFeature.this.getUtInterface();
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
IImsUt result = executeMethodAsyncForResult(() -> {
|
||||
try {
|
||||
return MmTelFeature.this.getUtInterface();
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return null;
|
||||
}
|
||||
}, "getUtInterface");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsEcbm getEcbmInterface() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
return MmTelFeature.this.getEcbmInterface();
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
IImsEcbm result = executeMethodAsyncForResult(() -> {
|
||||
try {
|
||||
return MmTelFeature.this.getEcbmInterface();
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return null;
|
||||
}
|
||||
}, "getEcbmInterface");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage),
|
||||
"setUiTtyMode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
return MmTelFeature.this.getMultiEndpointInterface();
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
IImsMultiEndpoint result = executeMethodAsyncForResult(() -> {
|
||||
try {
|
||||
return MmTelFeature.this.getMultiEndpointInterface();
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return null;
|
||||
}
|
||||
}, "getMultiEndpointInterface");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCapabilityStatus() {
|
||||
return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
|
||||
Integer result = executeMethodAsyncForResultNoException(() -> MmTelFeature.this
|
||||
.queryCapabilityStatus().mCapabilities, "queryCapabilityStatus");
|
||||
|
||||
if (result != null) {
|
||||
return result.intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCapabilityCallback(IImsCapabilityCallback c) {
|
||||
// no need to lock, structure already handles multithreading.
|
||||
MmTelFeature.this.addCapabilityCallback(c);
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.addCapabilityCallback(c), "addCapabilityCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCapabilityCallback(IImsCapabilityCallback c) {
|
||||
// no need to lock, structure already handles multithreading.
|
||||
MmTelFeature.this.removeCapabilityCallback(c);
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.removeCapabilityCallback(c), "removeCapabilityCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
|
||||
IImsCapabilityCallback c) {
|
||||
MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.requestChangeEnabledCapabilities(request, c),
|
||||
"changeCapabilitiesConfiguration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryCapabilityConfiguration(int capability, int radioTech,
|
||||
IImsCapabilityCallback c) {
|
||||
queryCapabilityConfigurationInternal(capability, radioTech, c);
|
||||
executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal(
|
||||
capability, radioTech, c), "queryCapabilityConfiguration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmsListener(IImsSmsListener l) {
|
||||
MmTelFeature.this.setSmsListener(l);
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
|
||||
"setSmsListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
|
||||
byte[] pdu) {
|
||||
synchronized (mLock) {
|
||||
MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
|
||||
}
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acknowledgeSms(int token, int messageRef, int result) {
|
||||
synchronized (mLock) {
|
||||
MmTelFeature.this.acknowledgeSms(token, messageRef, result);
|
||||
}
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.acknowledgeSms(token, messageRef, result), "acknowledgeSms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acknowledgeSmsReport(int token, int messageRef, int result) {
|
||||
synchronized (mLock) {
|
||||
MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
|
||||
}
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||
.acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSmsFormat() {
|
||||
synchronized (mLock) {
|
||||
return MmTelFeature.this.getSmsFormat();
|
||||
}
|
||||
return executeMethodAsyncForResultNoException(() -> MmTelFeature.this
|
||||
.getSmsFormat(), "getSmsFormat");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSmsReady() {
|
||||
synchronized (mLock) {
|
||||
MmTelFeature.this.onSmsReady();
|
||||
executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(),
|
||||
"onSmsReady");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r,
|
||||
String errorLogName) throws RemoteException {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResultNoException(Supplier<T> r,
|
||||
String errorLogName) {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -672,7 +783,12 @@ public class MmTelFeature extends ImsFeature {
|
||||
public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
|
||||
throws RemoteException {
|
||||
ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
|
||||
return s != null ? s.getServiceImpl() : null;
|
||||
if (s != null) {
|
||||
s.setDefaultExecutor(mExecutor);
|
||||
return s.getServiceImpl();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -713,7 +829,12 @@ public class MmTelFeature extends ImsFeature {
|
||||
*/
|
||||
protected IImsUt getUtInterface() throws RemoteException {
|
||||
ImsUtImplBase utImpl = getUt();
|
||||
return utImpl != null ? utImpl.getInterface() : null;
|
||||
if (utImpl != null) {
|
||||
utImpl.setDefaultExecutor(mExecutor);
|
||||
return utImpl.getInterface();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -721,7 +842,12 @@ public class MmTelFeature extends ImsFeature {
|
||||
*/
|
||||
protected IImsEcbm getEcbmInterface() throws RemoteException {
|
||||
ImsEcbmImplBase ecbmImpl = getEcbm();
|
||||
return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
|
||||
if (ecbmImpl != null) {
|
||||
ecbmImpl.setDefaultExecutor(mExecutor);
|
||||
return ecbmImpl.getImsEcbm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -729,7 +855,12 @@ public class MmTelFeature extends ImsFeature {
|
||||
*/
|
||||
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
|
||||
ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
|
||||
return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null;
|
||||
if (multiendpointImpl != null) {
|
||||
multiendpointImpl.setDefaultExecutor(mExecutor);
|
||||
return multiendpointImpl.getIImsMultiEndpoint();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -859,4 +990,16 @@ public class MmTelFeature extends ImsFeature {
|
||||
public final IImsMmTelFeature getBinder() {
|
||||
return mImsMMTelBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from ImsService.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of MmTelFeature.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
if (mExecutor == null) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class RcsFeature extends ImsFeature {
|
||||
// Reference the outer class in order to have better test coverage metrics instead of
|
||||
// creating a inner class referencing the outer class directly.
|
||||
private final RcsFeature mReference;
|
||||
private final Executor mExecutor;
|
||||
private Executor mExecutor;
|
||||
|
||||
RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
|
||||
mReference = classRef;
|
||||
@@ -259,7 +259,7 @@ public class RcsFeature extends ImsFeature {
|
||||
}
|
||||
}
|
||||
|
||||
private final Executor mExecutor;
|
||||
private Executor mExecutor;
|
||||
private final RcsFeatureBinder mImsRcsBinder;
|
||||
private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
|
||||
private CapabilityExchangeEventListener mCapExchangeEventListener;
|
||||
@@ -270,13 +270,9 @@ public class RcsFeature extends ImsFeature {
|
||||
* Method stubs called from the framework will be called asynchronously. To specify the
|
||||
* {@link Executor} that the methods stubs will be called, use
|
||||
* {@link RcsFeature#RcsFeature(Executor)} instead.
|
||||
*
|
||||
* @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature.
|
||||
*/
|
||||
@Deprecated
|
||||
public RcsFeature() {
|
||||
super();
|
||||
mExecutor = Runnable::run;
|
||||
// Run on the Binder threads that call them.
|
||||
mImsRcsBinder = new RcsFeatureBinder(this, mExecutor);
|
||||
}
|
||||
@@ -477,4 +473,17 @@ public class RcsFeature extends ImsFeature {
|
||||
return mCapabilityExchangeImpl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from ImsService.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of RcsFeature.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
if (mImsRcsBinder.mExecutor == null) {
|
||||
mExecutor = executor;
|
||||
mImsRcsBinder.mExecutor = executor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,20 @@ import android.telephony.ims.RtpHeaderExtension;
|
||||
import android.telephony.ims.RtpHeaderExtensionType;
|
||||
import android.telephony.ims.aidl.IImsCallSessionListener;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.ims.internal.IImsCallSession;
|
||||
import com.android.ims.internal.IImsVideoCallProvider;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Base implementation of IImsCallSession, which implements stub versions of the methods available.
|
||||
@@ -48,6 +56,8 @@ import java.util.Set;
|
||||
// DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
|
||||
// will break other implementations of ImsCallSession maintained by other ImsServices.
|
||||
public class ImsCallSessionImplBase implements AutoCloseable {
|
||||
|
||||
private static final String LOG_TAG = "ImsCallSessionImplBase";
|
||||
/**
|
||||
* Notify USSD Mode.
|
||||
*/
|
||||
@@ -110,185 +120,235 @@ public class ImsCallSessionImplBase implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private Executor mExecutor = Runnable::run;
|
||||
|
||||
// Non-final for injection by tests
|
||||
private IImsCallSession mServiceImpl = new IImsCallSession.Stub() {
|
||||
@Override
|
||||
public void close() {
|
||||
ImsCallSessionImplBase.this.close();
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCallId() {
|
||||
return ImsCallSessionImplBase.this.getCallId();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(),
|
||||
"getCallId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImsCallProfile getCallProfile() {
|
||||
return ImsCallSessionImplBase.this.getCallProfile();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(),
|
||||
"getCallProfile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImsCallProfile getLocalCallProfile() {
|
||||
return ImsCallSessionImplBase.this.getLocalCallProfile();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||
.getLocalCallProfile(), "getLocalCallProfile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImsCallProfile getRemoteCallProfile() {
|
||||
return ImsCallSessionImplBase.this.getRemoteCallProfile();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||
.getRemoteCallProfile(), "getRemoteCallProfile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String name) {
|
||||
return ImsCallSessionImplBase.this.getProperty(name);
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name),
|
||||
"getProperty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getState() {
|
||||
return ImsCallSessionImplBase.this.getState();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(),
|
||||
"getState");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInCall() {
|
||||
return ImsCallSessionImplBase.this.isInCall();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(),
|
||||
"isInCall");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(IImsCallSessionListener listener) {
|
||||
ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener));
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener(
|
||||
new ImsCallSessionListener(listener)), "setListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMute(boolean muted) {
|
||||
ImsCallSessionImplBase.this.setMute(muted);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(String callee, ImsCallProfile profile) {
|
||||
ImsCallSessionImplBase.this.start(callee, profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startConference(String[] participants, ImsCallProfile profile) throws
|
||||
RemoteException {
|
||||
ImsCallSessionImplBase.this.startConference(participants, profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants,
|
||||
profile), "startConference");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(int callType, ImsStreamMediaProfile profile) {
|
||||
ImsCallSessionImplBase.this.accept(callType, profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile),
|
||||
"accept");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deflect(String deflectNumber) {
|
||||
ImsCallSessionImplBase.this.deflect(deflectNumber);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber),
|
||||
"deflect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(int reason) {
|
||||
ImsCallSessionImplBase.this.reject(reason);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
|
||||
ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number,
|
||||
isConfirmationRequired), "transfer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
|
||||
ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
|
||||
otherSession.setServiceImpl(transferToSession);
|
||||
ImsCallSessionImplBase.this.transfer(otherSession);
|
||||
executeMethodAsync(() -> {
|
||||
ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
|
||||
otherSession.setServiceImpl(transferToSession);
|
||||
ImsCallSessionImplBase.this.transfer(otherSession);
|
||||
}, "consultativeTransfer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate(int reason) {
|
||||
ImsCallSessionImplBase.this.terminate(reason);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hold(ImsStreamMediaProfile profile) {
|
||||
ImsCallSessionImplBase.this.hold(profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume(ImsStreamMediaProfile profile) {
|
||||
ImsCallSessionImplBase.this.resume(profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge() {
|
||||
ImsCallSessionImplBase.this.merge();
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(int callType, ImsStreamMediaProfile profile) {
|
||||
ImsCallSessionImplBase.this.update(callType, profile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile),
|
||||
"update");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendToConference(String[] participants) {
|
||||
ImsCallSessionImplBase.this.extendToConference(participants);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants),
|
||||
"extendToConference");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inviteParticipants(String[] participants) {
|
||||
ImsCallSessionImplBase.this.inviteParticipants(participants);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants),
|
||||
"inviteParticipants");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeParticipants(String[] participants) {
|
||||
ImsCallSessionImplBase.this.removeParticipants(participants);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants),
|
||||
"removeParticipants");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDtmf(char c, Message result) {
|
||||
ImsCallSessionImplBase.this.sendDtmf(c, result);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDtmf(char c) {
|
||||
ImsCallSessionImplBase.this.startDtmf(c);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopDtmf() {
|
||||
ImsCallSessionImplBase.this.stopDtmf();
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendUssd(String ussdMessage) {
|
||||
ImsCallSessionImplBase.this.sendUssd(ussdMessage);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IImsVideoCallProvider getVideoCallProvider() {
|
||||
return ImsCallSessionImplBase.this.getVideoCallProvider();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||
.getVideoCallProvider(), "getVideoCallProvider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiparty() {
|
||||
return ImsCallSessionImplBase.this.isMultiparty();
|
||||
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(),
|
||||
"isMultiparty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRttModifyRequest(ImsCallProfile toProfile) {
|
||||
ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile),
|
||||
"sendRttModifyRequest");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRttModifyResponse(boolean status) {
|
||||
ImsCallSessionImplBase.this.sendRttModifyResponse(status);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status),
|
||||
"sendRttModifyResponse");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRttMessage(String rttMessage) {
|
||||
ImsCallSessionImplBase.this.sendRttMessage(rttMessage);
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage),
|
||||
"sendRttMessage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
|
||||
ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
|
||||
new ArraySet<RtpHeaderExtension>(extensions));
|
||||
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
|
||||
new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r,
|
||||
String errorLogName) {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -674,4 +734,14 @@ public class ImsCallSessionImplBase implements AutoCloseable {
|
||||
public void setServiceImpl(IImsCallSession serviceImpl) {
|
||||
mServiceImpl = serviceImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from MmTelFeature.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of ImsCallSession.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,21 @@ import android.util.Log;
|
||||
import com.android.ims.ImsConfig;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
/**
|
||||
* Controls the modification of IMS specific configurations. For more information on the supported
|
||||
@@ -81,21 +90,48 @@ public class ImsConfigImplBase {
|
||||
WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
|
||||
private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
|
||||
private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
|
||||
private final Object mLock = new Object();
|
||||
private Executor mExecutor;
|
||||
|
||||
@VisibleForTesting
|
||||
public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) {
|
||||
public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Executor executor) {
|
||||
mExecutor = executor;
|
||||
mImsConfigImplBaseWeakReference =
|
||||
new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
||||
getImsConfigImpl().addImsConfigCallback(c);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().addImsConfigCallback(c);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "addImsConfigCallback");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception addImsConfigCallback");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
||||
getImsConfigImpl().removeImsConfigCallback(c);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().removeImsConfigCallback(c);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "removeImsConfigCallback");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception removeImsConfigCallback");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,16 +144,34 @@ public class ImsConfigImplBase {
|
||||
* unavailable.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int getConfigInt(int item) throws RemoteException {
|
||||
if (mProvisionedIntValue.containsKey(item)) {
|
||||
return mProvisionedIntValue.get(item);
|
||||
} else {
|
||||
int retVal = getImsConfigImpl().getConfigInt(item);
|
||||
if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
|
||||
updateCachedValue(item, retVal, false);
|
||||
public int getConfigInt(int item) throws RemoteException {
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
int retVal = executeMethodAsyncForResult(()-> {
|
||||
int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
|
||||
synchronized (mLock) {
|
||||
if (mProvisionedIntValue.containsKey(item)) {
|
||||
return mProvisionedIntValue.get(item);
|
||||
} else {
|
||||
try {
|
||||
returnVal = getImsConfigImpl().getConfigInt(item);
|
||||
if (returnVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
|
||||
mProvisionedIntValue.put(item, returnVal);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
return returnVal;
|
||||
}, "getConfigInt");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,16 +183,34 @@ public class ImsConfigImplBase {
|
||||
* @return value in String format.
|
||||
*/
|
||||
@Override
|
||||
public synchronized String getConfigString(int item) throws RemoteException {
|
||||
if (mProvisionedStringValue.containsKey(item)) {
|
||||
return mProvisionedStringValue.get(item);
|
||||
} else {
|
||||
String retVal = getImsConfigImpl().getConfigString(item);
|
||||
if (retVal != null) {
|
||||
updateCachedValue(item, retVal, false);
|
||||
public String getConfigString(int item) throws RemoteException {
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
String retVal = executeMethodAsyncForResult(()-> {
|
||||
String returnVal = null;
|
||||
synchronized (mLock) {
|
||||
if (mProvisionedStringValue.containsKey(item)) {
|
||||
returnVal = mProvisionedStringValue.get(item);
|
||||
} else {
|
||||
try {
|
||||
returnVal = getImsConfigImpl().getConfigString(item);
|
||||
if (returnVal != null) {
|
||||
mProvisionedStringValue.put(item, returnVal);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
return returnVal;
|
||||
}, "getConfigString");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,14 +225,32 @@ public class ImsConfigImplBase {
|
||||
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int setConfigInt(int item, int value) throws RemoteException {
|
||||
mProvisionedIntValue.remove(item);
|
||||
int retVal = getImsConfigImpl().setConfig(item, value);
|
||||
if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||
updateCachedValue(item, value, true);
|
||||
} else {
|
||||
Log.d(TAG, "Set provision value of " + item +
|
||||
" to " + value + " failed with error code " + retVal);
|
||||
public int setConfigInt(int item, int value) throws RemoteException {
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
int retVal = executeMethodAsyncForResult(()-> {
|
||||
int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
mProvisionedIntValue.remove(item);
|
||||
returnVal = getImsConfigImpl().setConfig(item, value);
|
||||
if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||
mProvisionedIntValue.put(item, value);
|
||||
} else {
|
||||
Log.d(TAG, "Set provision value of " + item
|
||||
+ " to " + value + " failed with error code " + returnVal);
|
||||
}
|
||||
}
|
||||
notifyImsConfigChanged(item, value);
|
||||
return returnVal;
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return returnVal;
|
||||
}
|
||||
}, "setConfigInt");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
@@ -178,12 +268,30 @@ public class ImsConfigImplBase {
|
||||
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int setConfigString(int item, String value)
|
||||
public int setConfigString(int item, String value)
|
||||
throws RemoteException {
|
||||
mProvisionedStringValue.remove(item);
|
||||
int retVal = getImsConfigImpl().setConfig(item, value);
|
||||
if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||
updateCachedValue(item, value, true);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
int retVal = executeMethodAsyncForResult(()-> {
|
||||
int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
mProvisionedStringValue.remove(item);
|
||||
returnVal = getImsConfigImpl().setConfig(item, value);
|
||||
if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||
mProvisionedStringValue.put(item, value);
|
||||
}
|
||||
}
|
||||
notifyImsConfigChanged(item, value);
|
||||
return returnVal;
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
return returnVal;
|
||||
}
|
||||
}, "setConfigString");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
@@ -191,7 +299,19 @@ public class ImsConfigImplBase {
|
||||
|
||||
@Override
|
||||
public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
|
||||
getImsConfigImpl().updateImsCarrierConfigs(bundle);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().updateImsCarrierConfigs(bundle);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "updateImsCarrierConfigs");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception updateImsCarrierConfigs");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
|
||||
@@ -206,13 +326,37 @@ public class ImsConfigImplBase {
|
||||
@Override
|
||||
public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed)
|
||||
throws RemoteException {
|
||||
getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "notifyRcsAutoConfigurationReceived");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationReceived");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRcsAutoConfigurationRemoved()
|
||||
throws RemoteException {
|
||||
getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "notifyRcsAutoConfigurationRemoved");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationRemoved");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyImsConfigChanged(int item, int value) throws RemoteException {
|
||||
@@ -223,50 +367,144 @@ public class ImsConfigImplBase {
|
||||
getImsConfigImpl().notifyConfigChanged(item, value);
|
||||
}
|
||||
|
||||
protected synchronized void updateCachedValue(int item, int value, boolean notifyChange)
|
||||
throws RemoteException {
|
||||
mProvisionedIntValue.put(item, value);
|
||||
if (notifyChange) {
|
||||
notifyImsConfigChanged(item, value);
|
||||
protected void updateCachedValue(int item, int value) {
|
||||
synchronized (mLock) {
|
||||
mProvisionedIntValue.put(item, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void updateCachedValue(int item, String value,
|
||||
boolean notifyChange) throws RemoteException {
|
||||
mProvisionedStringValue.put(item, value);
|
||||
if (notifyChange) {
|
||||
notifyImsConfigChanged(item, value);
|
||||
protected void updateCachedValue(int item, String value) {
|
||||
synchronized (mLock) {
|
||||
mProvisionedStringValue.put(item, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
||||
getImsConfigImpl().addRcsConfigCallback(c);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().addRcsConfigCallback(c);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "addRcsConfigCallback");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception addRcsConfigCallback");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
||||
getImsConfigImpl().removeRcsConfigCallback(c);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().removeRcsConfigCallback(c);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "removeRcsConfigCallback");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception removeRcsConfigCallback");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRcsReconfiguration() throws RemoteException {
|
||||
getImsConfigImpl().triggerAutoConfiguration();
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().triggerAutoConfiguration();
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "triggerRcsReconfiguration");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception triggerRcsReconfiguration");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
|
||||
getImsConfigImpl().setRcsClientConfiguration(rcc);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
getImsConfigImpl().setRcsClientConfiguration(rcc);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "setRcsClientConfiguration");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception setRcsClientConfiguration");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
|
||||
notifyImsConfigChanged(item, value);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
notifyImsConfigChanged(item, value);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "notifyIntImsConfigChanged");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception notifyIntImsConfigChanged");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
|
||||
notifyImsConfigChanged(item, value);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(()-> {
|
||||
try {
|
||||
notifyImsConfigChanged(item, value);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "notifyStringImsConfigChanged");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
Log.d(TAG, "ImsConfigImplBase Exception notifyStringImsConfigChanged");
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r,
|
||||
String errorLogName) throws RemoteException {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,15 +541,24 @@ public class ImsConfigImplBase {
|
||||
ImsConfigStub mImsConfigStub;
|
||||
|
||||
/**
|
||||
* Used for compatibility between older versions of the ImsService.
|
||||
* Create a ImsConfig using the Executor specified for methods being called by the
|
||||
* framework.
|
||||
* @param executor The executor for the framework to use when executing the methods overridden
|
||||
* by the implementation of ImsConfig.
|
||||
*/
|
||||
public ImsConfigImplBase(@NonNull Executor executor) {
|
||||
mImsConfigStub = new ImsConfigStub(this, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ImsConfigImplBase(Context context) {
|
||||
mImsConfigStub = new ImsConfigStub(this);
|
||||
public ImsConfigImplBase(@NonNull Context context) {
|
||||
mImsConfigStub = new ImsConfigStub(this, null);
|
||||
}
|
||||
|
||||
public ImsConfigImplBase() {
|
||||
mImsConfigStub = new ImsConfigStub(this);
|
||||
mImsConfigStub = new ImsConfigStub(this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,8 +674,10 @@ public class ImsConfigImplBase {
|
||||
* @param value in Integer format.
|
||||
*/
|
||||
public final void notifyProvisionedValueChanged(int item, int value) {
|
||||
mImsConfigStub.updateCachedValue(item, value);
|
||||
|
||||
try {
|
||||
mImsConfigStub.updateCachedValue(item, value, true);
|
||||
mImsConfigStub.notifyImsConfigChanged(item, value);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead.");
|
||||
}
|
||||
@@ -443,8 +692,10 @@ public class ImsConfigImplBase {
|
||||
* @param value in String format.
|
||||
*/
|
||||
public final void notifyProvisionedValueChanged(int item, String value) {
|
||||
mImsConfigStub.updateCachedValue(item, value);
|
||||
|
||||
try {
|
||||
mImsConfigStub.updateCachedValue(item, value, true);
|
||||
mImsConfigStub.notifyImsConfigChanged(item, value);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead.");
|
||||
}
|
||||
@@ -582,4 +833,16 @@ public class ImsConfigImplBase {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from ImsService.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of ImsConfig.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
if (mImsConfigStub.mExecutor == null) {
|
||||
mImsConfigStub.mExecutor = executor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,21 @@
|
||||
|
||||
package android.telephony.ims.stub;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.ims.internal.IImsEcbm;
|
||||
import com.android.ims.internal.IImsEcbmListener;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
|
||||
/**
|
||||
* Base implementation of ImsEcbm, which implements stub versions of the methods
|
||||
@@ -40,10 +47,12 @@ public class ImsEcbmImplBase {
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private IImsEcbmListener mListener;
|
||||
private Executor mExecutor = Runnable::run;
|
||||
|
||||
private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
|
||||
@Override
|
||||
public void setListener(IImsEcbmListener listener) {
|
||||
synchronized (mLock) {
|
||||
executeMethodAsync(() -> {
|
||||
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
||||
Log.w(TAG, "setListener: discarding dead Binder");
|
||||
mListener = null;
|
||||
@@ -62,12 +71,25 @@ public class ImsEcbmImplBase {
|
||||
+ "listener");
|
||||
mListener = listener;
|
||||
}
|
||||
}
|
||||
}, "setListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEmergencyCallbackMode() {
|
||||
ImsEcbmImplBase.this.exitEmergencyCallbackMode();
|
||||
executeMethodAsync(() -> ImsEcbmImplBase.this.exitEmergencyCallbackMode(),
|
||||
"exitEmergencyCallbackMode");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(TAG, "ImsEcbmImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -123,4 +145,14 @@ public class ImsEcbmImplBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from MmTelFeature.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of ImsEcbm.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.telephony.ims.stub;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.RemoteException;
|
||||
import android.telephony.ims.ImsExternalCallState;
|
||||
@@ -23,9 +24,14 @@ import android.util.Log;
|
||||
|
||||
import com.android.ims.internal.IImsExternalCallStateListener;
|
||||
import com.android.ims.internal.IImsMultiEndpoint;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
|
||||
@@ -43,11 +49,13 @@ public class ImsMultiEndpointImplBase {
|
||||
|
||||
private IImsExternalCallStateListener mListener;
|
||||
private final Object mLock = new Object();
|
||||
private Executor mExecutor = Runnable::run;
|
||||
|
||||
private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
|
||||
|
||||
@Override
|
||||
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
executeMethodAsync(() -> {
|
||||
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
||||
Log.w(TAG, "setListener: discarding dead Binder");
|
||||
mListener = null;
|
||||
@@ -67,12 +75,25 @@ public class ImsMultiEndpointImplBase {
|
||||
+ "listener");
|
||||
mListener = listener;
|
||||
}
|
||||
}
|
||||
}, "setListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestImsExternalCallStateInfo() throws RemoteException {
|
||||
ImsMultiEndpointImplBase.this.requestImsExternalCallStateInfo();
|
||||
executeMethodAsync(() -> ImsMultiEndpointImplBase.this
|
||||
.requestImsExternalCallStateInfo(), "requestImsExternalCallStateInfo");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(TAG, "ImsMultiEndpointImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,4 +129,14 @@ public class ImsMultiEndpointImplBase {
|
||||
public void requestImsExternalCallStateInfo() {
|
||||
Log.d(TAG, "requestImsExternalCallStateInfo() not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from MmTelFeature.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of ImsMultiEndpoint.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,19 @@ import android.telephony.ims.aidl.IImsRegistrationCallback;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Controls IMS registration for this ImsService and notifies the framework when the IMS
|
||||
@@ -92,39 +101,114 @@ public class ImsRegistrationImplBase {
|
||||
// yet.
|
||||
private static final int REGISTRATION_STATE_UNKNOWN = -1;
|
||||
|
||||
private Executor mExecutor;
|
||||
|
||||
/**
|
||||
* Create a new ImsRegistration.
|
||||
* <p>
|
||||
* Method stubs called from the framework will be called asynchronously. To specify the
|
||||
* {@link Executor} that the methods stubs will be called, use
|
||||
* {@link ImsRegistrationImplBase#ImsRegistrationImplBase(Executor)} instead.
|
||||
*/
|
||||
public ImsRegistrationImplBase() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ImsRegistration using the Executor specified for methods being called by the
|
||||
* framework.
|
||||
* @param executor The executor for the framework to use when executing the methods overridden
|
||||
* by the implementation of ImsRegistration.
|
||||
*/
|
||||
public ImsRegistrationImplBase(@NonNull Executor executor) {
|
||||
super();
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
private final IImsRegistration mBinder = new IImsRegistration.Stub() {
|
||||
|
||||
@Override
|
||||
public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
|
||||
: mRegistrationAttributes.getRegistrationTechnology();
|
||||
}
|
||||
return executeMethodAsyncForResult(() -> (mRegistrationAttributes == null)
|
||||
? REGISTRATION_TECH_NONE : mRegistrationAttributes.getRegistrationTechnology(),
|
||||
"getRegistrationTechnology");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
||||
ImsRegistrationImplBase.this.addRegistrationCallback(c);
|
||||
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||
executeMethodAsync(() -> {
|
||||
try {
|
||||
ImsRegistrationImplBase.this.addRegistrationCallback(c);
|
||||
} catch (RemoteException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}, "addRegistrationCallback");
|
||||
|
||||
if (exceptionRef.get() != null) {
|
||||
throw exceptionRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
||||
ImsRegistrationImplBase.this.removeRegistrationCallback(c);
|
||||
executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c),
|
||||
"removeRegistrationCallback");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerFullNetworkRegistration(int sipCode, String sipReason) {
|
||||
ImsRegistrationImplBase.this.triggerFullNetworkRegistration(sipCode, sipReason);
|
||||
executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
|
||||
.triggerFullNetworkRegistration(sipCode, sipReason),
|
||||
"triggerFullNetworkRegistration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerUpdateSipDelegateRegistration() {
|
||||
ImsRegistrationImplBase.this.updateSipDelegateRegistration();
|
||||
executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
|
||||
.updateSipDelegateRegistration(), "triggerUpdateSipDelegateRegistration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerSipDelegateDeregistration() {
|
||||
ImsRegistrationImplBase.this.triggerSipDelegateDeregistration();
|
||||
executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
|
||||
.triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r,
|
||||
String errorLogName) throws RemoteException {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -394,4 +478,16 @@ public class ImsRegistrationImplBase {
|
||||
onSubscriberAssociatedUriChanged(c, uris);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from ImsService.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of Registration.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
if (mExecutor == null) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,17 @@ import android.util.Log;
|
||||
|
||||
import com.android.ims.internal.IImsUt;
|
||||
import com.android.ims.internal.IImsUtListener;
|
||||
import com.android.internal.telephony.util.TelephonyUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Base implementation of IMS UT interface, which implements stubs. Override these methods to
|
||||
@@ -119,96 +126,108 @@ public class ImsUtImplBase {
|
||||
*/
|
||||
public static final int INVALID_RESULT = -1;
|
||||
|
||||
private Executor mExecutor = Runnable::run;
|
||||
|
||||
private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
|
||||
private final Object mLock = new Object();
|
||||
private ImsUtListener mUtListener;
|
||||
|
||||
@Override
|
||||
public void close() throws RemoteException {
|
||||
ImsUtImplBase.this.close();
|
||||
executeMethodAsync(() ->ImsUtImplBase.this.close(), "close");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCallBarring(int cbType) throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCallBarring(cbType);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallBarring(cbType),
|
||||
"queryCallBarring");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCallForward(int condition, String number) throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCallForward(condition, number);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallForward(
|
||||
condition, number), "queryCallForward");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCallWaiting() throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCallWaiting();
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallWaiting(),
|
||||
"queryCallWaiting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCLIR() throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCLIR();
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIR(), "queryCLIR");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCLIP() throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCLIP();
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIP(), "queryCLIP");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCOLR() throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCOLR();
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLR(), "queryCOLR");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCOLP() throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCOLP();
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLP(), "queryCOLP");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int transact(Bundle ssInfo) throws RemoteException {
|
||||
return ImsUtImplBase.this.transact(ssInfo);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.transact(ssInfo),
|
||||
"transact");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCallBarring(int cbType, int action, String[] barrList) throws
|
||||
RemoteException {
|
||||
return ImsUtImplBase.this.updateCallBarring(cbType, action, barrList);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallBarring(
|
||||
cbType, action, barrList), "updateCallBarring");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCallForward(int action, int condition, String number, int serviceClass,
|
||||
int timeSeconds) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCallForward(action, condition, number, serviceClass,
|
||||
timeSeconds);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallForward(
|
||||
action, condition, number, serviceClass, timeSeconds), "updateCallForward");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCallWaiting(enable, serviceClass);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallWaiting(
|
||||
enable, serviceClass), "updateCallWaiting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCLIR(int clirMode) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCLIR(clirMode);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIR(clirMode),
|
||||
"updateCLIR");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCLIP(boolean enable) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCLIP(enable);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIP(enable),
|
||||
"updateCLIP");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCOLR(int presentation) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCOLR(presentation);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLR(presentation),
|
||||
"updateCOLR");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCOLP(boolean enable) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCOLP(enable);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLP(enable),
|
||||
"updateCOLP");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(IImsUtListener listener) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
executeMethodAsync(() -> {
|
||||
if (mUtListener != null
|
||||
&& !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
|
||||
Log.w(TAG, "setListener: discarding dead Binder");
|
||||
@@ -229,29 +248,59 @@ public class ImsUtImplBase {
|
||||
+ "listener");
|
||||
mUtListener = new ImsUtListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
ImsUtImplBase.this.setListener(mUtListener);
|
||||
ImsUtImplBase.this.setListener(mUtListener);
|
||||
}, "setListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int queryCallBarringForServiceClass(int cbType, int serviceClass)
|
||||
throws RemoteException {
|
||||
return ImsUtImplBase.this.queryCallBarringForServiceClass(cbType, serviceClass);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||
.queryCallBarringForServiceClass(cbType, serviceClass),
|
||||
"queryCallBarringForServiceClass");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCallBarringForServiceClass(int cbType, int action,
|
||||
String[] barrList, int serviceClass) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCallBarringForServiceClass(
|
||||
cbType, action, barrList, serviceClass);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||
.updateCallBarringForServiceClass(cbType, action, barrList, serviceClass),
|
||||
"updateCallBarringForServiceClass");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
|
||||
int serviceClass, String password) throws RemoteException {
|
||||
return ImsUtImplBase.this.updateCallBarringWithPassword(
|
||||
cbType, action, barrList, serviceClass, password);
|
||||
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||
.updateCallBarringWithPassword(cbType, action, barrList, serviceClass,
|
||||
password), "updateCallBarringWithPassword");
|
||||
}
|
||||
|
||||
// Call the methods with a clean calling identity on the executor and wait indefinitely for
|
||||
// the future to return.
|
||||
private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
|
||||
try {
|
||||
CompletableFuture.runAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
|
||||
} catch (CancellationException | CompletionException e) {
|
||||
Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T executeMethodAsyncForResult(Supplier<T> r,
|
||||
String errorLogName) throws RemoteException {
|
||||
CompletableFuture<T> future = CompletableFuture.supplyAsync(
|
||||
() -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
|
||||
try {
|
||||
return future.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
|
||||
+ e.getMessage());
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -470,4 +519,14 @@ public class ImsUtImplBase {
|
||||
public IImsUt getInterface() {
|
||||
return mServiceImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from MmTelFeature.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of ImsUT.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
mExecutor = executor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,9 +86,20 @@ public class SipTransportImplBase {
|
||||
}
|
||||
};
|
||||
|
||||
private final Executor mBinderExecutor;
|
||||
private Executor mBinderExecutor;
|
||||
private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Create a new SipTransport.
|
||||
* <p>
|
||||
* Method stubs called from the framework will be called asynchronously. To specify the
|
||||
* {@link Executor} that the methods stubs will be called, use
|
||||
* {@link SipTransportImplBase#SipTransportImplBase(Executor)} instead.
|
||||
*/
|
||||
public SipTransportImplBase() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an implementation of SipTransportImplBase.
|
||||
*
|
||||
@@ -212,4 +223,16 @@ public class SipTransportImplBase {
|
||||
public ISipTransport getBinder() {
|
||||
return mSipTransportImpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default Executor from ImsService.
|
||||
* @param executor The default executor for the framework to use when executing the methods
|
||||
* overridden by the implementation of SipTransport.
|
||||
* @hide
|
||||
*/
|
||||
public final void setDefaultExecutor(@NonNull Executor executor) {
|
||||
if (mBinderExecutor == null) {
|
||||
mBinderExecutor = executor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user