(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 Change-Id: I10621f9a767ba5bc55373f49caf426e66adbec77
This commit is contained in:
@@ -13506,6 +13506,7 @@ package android.telephony.ims {
|
|||||||
method public void disableIms(int);
|
method public void disableIms(int);
|
||||||
method public void enableIms(int);
|
method public void enableIms(int);
|
||||||
method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
|
method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
|
||||||
|
method @NonNull public java.util.concurrent.Executor getExecutor();
|
||||||
method public long getImsServiceCapabilities();
|
method public long getImsServiceCapabilities();
|
||||||
method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
|
method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
|
||||||
method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
|
method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
|
||||||
@@ -14121,6 +14122,7 @@ package android.telephony.ims.feature {
|
|||||||
|
|
||||||
public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
|
public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
|
||||||
ctor public MmTelFeature();
|
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 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 public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
|
||||||
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
|
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
|
||||||
@@ -14154,7 +14156,7 @@ package android.telephony.ims.feature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
|
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
|
||||||
ctor @Deprecated public RcsFeature();
|
ctor public RcsFeature();
|
||||||
ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
|
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 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);
|
method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
|
||||||
@@ -14258,6 +14260,7 @@ package android.telephony.ims.stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ImsConfigImplBase {
|
public class ImsConfigImplBase {
|
||||||
|
ctor public ImsConfigImplBase(@NonNull java.util.concurrent.Executor);
|
||||||
ctor public ImsConfigImplBase();
|
ctor public ImsConfigImplBase();
|
||||||
method public int getConfigInt(int);
|
method public int getConfigInt(int);
|
||||||
method public String getConfigString(int);
|
method public String getConfigString(int);
|
||||||
@@ -14310,6 +14313,7 @@ package android.telephony.ims.stub {
|
|||||||
|
|
||||||
public class ImsRegistrationImplBase {
|
public class ImsRegistrationImplBase {
|
||||||
ctor public 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 onDeregistered(android.telephony.ims.ImsReasonInfo);
|
||||||
method public final void onRegistered(int);
|
method public final void onRegistered(int);
|
||||||
method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
|
method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
|
||||||
@@ -14422,6 +14426,7 @@ package android.telephony.ims.stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class SipTransportImplBase {
|
public class SipTransportImplBase {
|
||||||
|
ctor public SipTransportImplBase();
|
||||||
ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
|
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 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);
|
method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package android.telephony.ims;
|
package android.telephony.ims;
|
||||||
|
|
||||||
import android.annotation.LongDef;
|
import android.annotation.LongDef;
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
@@ -44,11 +45,18 @@ import android.util.SparseArray;
|
|||||||
|
|
||||||
import com.android.ims.internal.IImsFeatureStatusCallback;
|
import com.android.ims.internal.IImsFeatureStatusCallback;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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
|
* 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 final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
|
||||||
|
|
||||||
private IImsServiceControllerListener mListener;
|
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.
|
* Listener that notifies the framework of ImsService changes.
|
||||||
@@ -201,38 +223,45 @@ public class ImsService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsMmTelFeature createMmTelFeature(int slotId) {
|
public IImsMmTelFeature createMmTelFeature(int slotId) {
|
||||||
return createMmTelFeatureInternal(slotId);
|
return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
|
||||||
|
"createMmTelFeature");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsRcsFeature createRcsFeature(int slotId) {
|
public IImsRcsFeature createRcsFeature(int slotId) {
|
||||||
return createRcsFeatureInternal(slotId);
|
return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
|
||||||
|
"createRcsFeature");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addFeatureStatusCallback(int slotId, int featureType,
|
public void addFeatureStatusCallback(int slotId, int featureType,
|
||||||
IImsFeatureStatusCallback c) {
|
IImsFeatureStatusCallback c) {
|
||||||
ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
|
executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback(
|
||||||
|
slotId, featureType, c), "addFeatureStatusCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeFeatureStatusCallback(int slotId, int featureType,
|
public void removeFeatureStatusCallback(int slotId, int featureType,
|
||||||
IImsFeatureStatusCallback c) {
|
IImsFeatureStatusCallback c) {
|
||||||
ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
|
executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback(
|
||||||
|
slotId, featureType, c), "removeFeatureStatusCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeImsFeature(int slotId, int featureType) {
|
public void removeImsFeature(int slotId, int featureType) {
|
||||||
ImsService.this.removeImsFeature(slotId, featureType);
|
executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
|
||||||
|
"removeImsFeature");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImsFeatureConfiguration querySupportedImsFeatures() {
|
public ImsFeatureConfiguration querySupportedImsFeatures() {
|
||||||
return ImsService.this.querySupportedImsFeatures();
|
return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(),
|
||||||
|
"ImsFeatureConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getImsServiceCapabilities() {
|
public long getImsServiceCapabilities() {
|
||||||
|
return executeMethodAsyncForResult(() -> {
|
||||||
long caps = ImsService.this.getImsServiceCapabilities();
|
long caps = ImsService.this.getImsServiceCapabilities();
|
||||||
long sanitizedCaps = sanitizeCapabilities(caps);
|
long sanitizedCaps = sanitizeCapabilities(caps);
|
||||||
if (caps != sanitizedCaps) {
|
if (caps != sanitizedCaps) {
|
||||||
@@ -240,39 +269,86 @@ public class ImsService extends Service {
|
|||||||
+ Long.toHexString(caps ^ sanitizedCaps));
|
+ Long.toHexString(caps ^ sanitizedCaps));
|
||||||
}
|
}
|
||||||
return sanitizedCaps;
|
return sanitizedCaps;
|
||||||
|
}, "getImsServiceCapabilities");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyImsServiceReadyForFeatureCreation() {
|
public void notifyImsServiceReadyForFeatureCreation() {
|
||||||
ImsService.this.readyForFeatureCreation();
|
executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(),
|
||||||
|
"notifyImsServiceReadyForFeatureCreation");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsConfig getConfig(int slotId) {
|
public IImsConfig getConfig(int slotId) {
|
||||||
|
return executeMethodAsyncForResult(() -> {
|
||||||
ImsConfigImplBase c = ImsService.this.getConfig(slotId);
|
ImsConfigImplBase c = ImsService.this.getConfig(slotId);
|
||||||
return c != null ? c.getIImsConfig() : null;
|
if (c != null) {
|
||||||
|
c.setDefaultExecutor(mExecutor);
|
||||||
|
return c.getIImsConfig();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, "getConfig");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsRegistration getRegistration(int slotId) {
|
public IImsRegistration getRegistration(int slotId) {
|
||||||
|
return executeMethodAsyncForResult(() -> {
|
||||||
ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
|
ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
|
||||||
return r != null ? r.getBinder() : null;
|
if (r != null) {
|
||||||
|
r.setDefaultExecutor(mExecutor);
|
||||||
|
return r.getBinder();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, "getRegistration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ISipTransport getSipTransport(int slotId) {
|
public ISipTransport getSipTransport(int slotId) {
|
||||||
|
return executeMethodAsyncForResult(() -> {
|
||||||
SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
|
SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
|
||||||
return s != null ? s.getBinder() : null;
|
if (s != null) {
|
||||||
|
s.setDefaultExecutor(mExecutor);
|
||||||
|
return s.getBinder();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, "getSipTransport");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enableIms(int slotId) {
|
public void enableIms(int slotId) {
|
||||||
ImsService.this.enableIms(slotId);
|
executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disableIms(int slotId) {
|
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);
|
MmTelFeature f = createMmTelFeature(slotId);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
|
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
|
||||||
|
f.setDefaultExecutor(mExecutor);
|
||||||
return f.getBinder();
|
return f.getBinder();
|
||||||
} else {
|
} else {
|
||||||
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
|
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
|
||||||
@@ -310,6 +387,7 @@ public class ImsService extends Service {
|
|||||||
private IImsRcsFeature createRcsFeatureInternal(int slotId) {
|
private IImsRcsFeature createRcsFeatureInternal(int slotId) {
|
||||||
RcsFeature f = createRcsFeature(slotId);
|
RcsFeature f = createRcsFeature(slotId);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
|
f.setDefaultExecutor(mExecutor);
|
||||||
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
|
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
|
||||||
return f.getBinder();
|
return f.getBinder();
|
||||||
} else {
|
} else {
|
||||||
@@ -562,4 +640,15 @@ public class ImsService extends Service {
|
|||||||
result.append("}");
|
result.append("}");
|
||||||
return result.toString();
|
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.ImsSmsImplBase;
|
||||||
import android.telephony.ims.stub.ImsUtImplBase;
|
import android.telephony.ims.stub.ImsUtImplBase;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.ims.internal.IImsCallSession;
|
import com.android.ims.internal.IImsCallSession;
|
||||||
import com.android.ims.internal.IImsEcbm;
|
import com.android.ims.internal.IImsEcbm;
|
||||||
import com.android.ims.internal.IImsMultiEndpoint;
|
import com.android.ims.internal.IImsMultiEndpoint;
|
||||||
import com.android.ims.internal.IImsUt;
|
import com.android.ims.internal.IImsUt;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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.
|
* 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 {
|
public class MmTelFeature extends ImsFeature {
|
||||||
|
|
||||||
private static final String LOG_TAG = "MmTelFeature";
|
private static final String LOG_TAG = "MmTelFeature";
|
||||||
|
private Executor mExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
@@ -68,160 +78,261 @@ public class MmTelFeature extends ImsFeature {
|
|||||||
public MmTelFeature() {
|
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() {
|
private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setListener(IImsMmTelListener l) {
|
public void setListener(IImsMmTelListener l) {
|
||||||
MmTelFeature.this.setListener(l);
|
executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFeatureState() throws RemoteException {
|
public int getFeatureState() throws RemoteException {
|
||||||
try {
|
return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(),
|
||||||
return MmTelFeature.this.getFeatureState();
|
"getFeatureState");
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RemoteException(e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImsCallProfile createCallProfile(int callSessionType, int callType)
|
public ImsCallProfile createCallProfile(int callSessionType, int callType)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
synchronized (mLock) {
|
return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile(
|
||||||
try {
|
callSessionType, callType), "createCallProfile");
|
||||||
return MmTelFeature.this.createCallProfile(callSessionType, callType);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RemoteException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
|
public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
synchronized (mLock) {
|
executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(
|
||||||
try {
|
new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes");
|
||||||
MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RemoteException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
|
public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
|
||||||
synchronized (mLock) {
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
IImsCallSession result = executeMethodAsyncForResult(() -> {
|
||||||
|
try {
|
||||||
return createCallSessionInterface(profile);
|
return createCallSessionInterface(profile);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}, "createCallSession");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int shouldProcessCall(String[] numbers) {
|
public int shouldProcessCall(String[] numbers) {
|
||||||
synchronized (mLock) {
|
Integer result = executeMethodAsyncForResultNoException(() ->
|
||||||
return MmTelFeature.this.shouldProcessCall(numbers);
|
MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall");
|
||||||
|
if (result != null) {
|
||||||
|
return result.intValue();
|
||||||
|
} else {
|
||||||
|
return PROCESS_CALL_CSFB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsUt getUtInterface() throws RemoteException {
|
public IImsUt getUtInterface() throws RemoteException {
|
||||||
synchronized (mLock) {
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
IImsUt result = executeMethodAsyncForResult(() -> {
|
||||||
|
try {
|
||||||
return MmTelFeature.this.getUtInterface();
|
return MmTelFeature.this.getUtInterface();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}, "getUtInterface");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsEcbm getEcbmInterface() throws RemoteException {
|
public IImsEcbm getEcbmInterface() throws RemoteException {
|
||||||
synchronized (mLock) {
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
IImsEcbm result = executeMethodAsyncForResult(() -> {
|
||||||
|
try {
|
||||||
return MmTelFeature.this.getEcbmInterface();
|
return MmTelFeature.this.getEcbmInterface();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}, "getEcbmInterface");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
|
public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
|
||||||
synchronized (mLock) {
|
executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage),
|
||||||
try {
|
"setUiTtyMode");
|
||||||
MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RemoteException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
|
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
|
||||||
synchronized (mLock) {
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
IImsMultiEndpoint result = executeMethodAsyncForResult(() -> {
|
||||||
|
try {
|
||||||
return MmTelFeature.this.getMultiEndpointInterface();
|
return MmTelFeature.this.getMultiEndpointInterface();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
}, "getMultiEndpointInterface");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCapabilityStatus() {
|
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
|
@Override
|
||||||
public void addCapabilityCallback(IImsCapabilityCallback c) {
|
public void addCapabilityCallback(IImsCapabilityCallback c) {
|
||||||
// no need to lock, structure already handles multithreading.
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
MmTelFeature.this.addCapabilityCallback(c);
|
.addCapabilityCallback(c), "addCapabilityCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeCapabilityCallback(IImsCapabilityCallback c) {
|
public void removeCapabilityCallback(IImsCapabilityCallback c) {
|
||||||
// no need to lock, structure already handles multithreading.
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
MmTelFeature.this.removeCapabilityCallback(c);
|
.removeCapabilityCallback(c), "removeCapabilityCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
|
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
|
||||||
IImsCapabilityCallback c) {
|
IImsCapabilityCallback c) {
|
||||||
MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
|
.requestChangeEnabledCapabilities(request, c),
|
||||||
|
"changeCapabilitiesConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queryCapabilityConfiguration(int capability, int radioTech,
|
public void queryCapabilityConfiguration(int capability, int radioTech,
|
||||||
IImsCapabilityCallback c) {
|
IImsCapabilityCallback c) {
|
||||||
queryCapabilityConfigurationInternal(capability, radioTech, c);
|
executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal(
|
||||||
|
capability, radioTech, c), "queryCapabilityConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSmsListener(IImsSmsListener l) {
|
public void setSmsListener(IImsSmsListener l) {
|
||||||
MmTelFeature.this.setSmsListener(l);
|
executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
|
||||||
|
"setSmsListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
|
public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
|
||||||
byte[] pdu) {
|
byte[] pdu) {
|
||||||
synchronized (mLock) {
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
|
.sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acknowledgeSms(int token, int messageRef, int result) {
|
public void acknowledgeSms(int token, int messageRef, int result) {
|
||||||
synchronized (mLock) {
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
MmTelFeature.this.acknowledgeSms(token, messageRef, result);
|
.acknowledgeSms(token, messageRef, result), "acknowledgeSms");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acknowledgeSmsReport(int token, int messageRef, int result) {
|
public void acknowledgeSmsReport(int token, int messageRef, int result) {
|
||||||
synchronized (mLock) {
|
executeMethodAsyncNoException(() -> MmTelFeature.this
|
||||||
MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
|
.acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSmsFormat() {
|
public String getSmsFormat() {
|
||||||
synchronized (mLock) {
|
return executeMethodAsyncForResultNoException(() -> MmTelFeature.this
|
||||||
return MmTelFeature.this.getSmsFormat();
|
.getSmsFormat(), "getSmsFormat");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSmsReady() {
|
public void onSmsReady() {
|
||||||
synchronized (mLock) {
|
executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(),
|
||||||
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)
|
public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
|
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 {
|
protected IImsUt getUtInterface() throws RemoteException {
|
||||||
ImsUtImplBase utImpl = getUt();
|
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 {
|
protected IImsEcbm getEcbmInterface() throws RemoteException {
|
||||||
ImsEcbmImplBase ecbmImpl = getEcbm();
|
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 {
|
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
|
||||||
ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
|
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() {
|
public final IImsMmTelFeature getBinder() {
|
||||||
return mImsMMTelBinder;
|
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
|
// Reference the outer class in order to have better test coverage metrics instead of
|
||||||
// creating a inner class referencing the outer class directly.
|
// creating a inner class referencing the outer class directly.
|
||||||
private final RcsFeature mReference;
|
private final RcsFeature mReference;
|
||||||
private final Executor mExecutor;
|
private Executor mExecutor;
|
||||||
|
|
||||||
RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
|
RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
|
||||||
mReference = classRef;
|
mReference = classRef;
|
||||||
@@ -259,7 +259,7 @@ public class RcsFeature extends ImsFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Executor mExecutor;
|
private Executor mExecutor;
|
||||||
private final RcsFeatureBinder mImsRcsBinder;
|
private final RcsFeatureBinder mImsRcsBinder;
|
||||||
private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
|
private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
|
||||||
private CapabilityExchangeEventListener mCapExchangeEventListener;
|
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
|
* Method stubs called from the framework will be called asynchronously. To specify the
|
||||||
* {@link Executor} that the methods stubs will be called, use
|
* {@link Executor} that the methods stubs will be called, use
|
||||||
* {@link RcsFeature#RcsFeature(Executor)} instead.
|
* {@link RcsFeature#RcsFeature(Executor)} instead.
|
||||||
*
|
|
||||||
* @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public RcsFeature() {
|
public RcsFeature() {
|
||||||
super();
|
super();
|
||||||
mExecutor = Runnable::run;
|
|
||||||
// Run on the Binder threads that call them.
|
// Run on the Binder threads that call them.
|
||||||
mImsRcsBinder = new RcsFeatureBinder(this, mExecutor);
|
mImsRcsBinder = new RcsFeatureBinder(this, mExecutor);
|
||||||
}
|
}
|
||||||
@@ -477,4 +473,17 @@ public class RcsFeature extends ImsFeature {
|
|||||||
return mCapabilityExchangeImpl;
|
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.RtpHeaderExtensionType;
|
||||||
import android.telephony.ims.aidl.IImsCallSessionListener;
|
import android.telephony.ims.aidl.IImsCallSessionListener;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.ims.internal.IImsCallSession;
|
import com.android.ims.internal.IImsCallSession;
|
||||||
import com.android.ims.internal.IImsVideoCallProvider;
|
import com.android.ims.internal.IImsVideoCallProvider;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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.
|
* 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
|
// 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.
|
// will break other implementations of ImsCallSession maintained by other ImsServices.
|
||||||
public class ImsCallSessionImplBase implements AutoCloseable {
|
public class ImsCallSessionImplBase implements AutoCloseable {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "ImsCallSessionImplBase";
|
||||||
/**
|
/**
|
||||||
* Notify USSD Mode.
|
* Notify USSD Mode.
|
||||||
*/
|
*/
|
||||||
@@ -110,185 +120,235 @@ public class ImsCallSessionImplBase implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Executor mExecutor = Runnable::run;
|
||||||
|
|
||||||
// Non-final for injection by tests
|
// Non-final for injection by tests
|
||||||
private IImsCallSession mServiceImpl = new IImsCallSession.Stub() {
|
private IImsCallSession mServiceImpl = new IImsCallSession.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
ImsCallSessionImplBase.this.close();
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCallId() {
|
public String getCallId() {
|
||||||
return ImsCallSessionImplBase.this.getCallId();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(),
|
||||||
|
"getCallId");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImsCallProfile getCallProfile() {
|
public ImsCallProfile getCallProfile() {
|
||||||
return ImsCallSessionImplBase.this.getCallProfile();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(),
|
||||||
|
"getCallProfile");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImsCallProfile getLocalCallProfile() {
|
public ImsCallProfile getLocalCallProfile() {
|
||||||
return ImsCallSessionImplBase.this.getLocalCallProfile();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||||
|
.getLocalCallProfile(), "getLocalCallProfile");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImsCallProfile getRemoteCallProfile() {
|
public ImsCallProfile getRemoteCallProfile() {
|
||||||
return ImsCallSessionImplBase.this.getRemoteCallProfile();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||||
|
.getRemoteCallProfile(), "getRemoteCallProfile");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProperty(String name) {
|
public String getProperty(String name) {
|
||||||
return ImsCallSessionImplBase.this.getProperty(name);
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name),
|
||||||
|
"getProperty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getState() {
|
public int getState() {
|
||||||
return ImsCallSessionImplBase.this.getState();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(),
|
||||||
|
"getState");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInCall() {
|
public boolean isInCall() {
|
||||||
return ImsCallSessionImplBase.this.isInCall();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(),
|
||||||
|
"isInCall");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setListener(IImsCallSessionListener listener) {
|
public void setListener(IImsCallSessionListener listener) {
|
||||||
ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener));
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener(
|
||||||
|
new ImsCallSessionListener(listener)), "setListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMute(boolean muted) {
|
public void setMute(boolean muted) {
|
||||||
ImsCallSessionImplBase.this.setMute(muted);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(String callee, ImsCallProfile profile) {
|
public void start(String callee, ImsCallProfile profile) {
|
||||||
ImsCallSessionImplBase.this.start(callee, profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startConference(String[] participants, ImsCallProfile profile) throws
|
public void startConference(String[] participants, ImsCallProfile profile) throws
|
||||||
RemoteException {
|
RemoteException {
|
||||||
ImsCallSessionImplBase.this.startConference(participants, profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants,
|
||||||
|
profile), "startConference");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(int callType, ImsStreamMediaProfile profile) {
|
public void accept(int callType, ImsStreamMediaProfile profile) {
|
||||||
ImsCallSessionImplBase.this.accept(callType, profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile),
|
||||||
|
"accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deflect(String deflectNumber) {
|
public void deflect(String deflectNumber) {
|
||||||
ImsCallSessionImplBase.this.deflect(deflectNumber);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber),
|
||||||
|
"deflect");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reject(int reason) {
|
public void reject(int reason) {
|
||||||
ImsCallSessionImplBase.this.reject(reason);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
|
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
|
||||||
ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number,
|
||||||
|
isConfirmationRequired), "transfer");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
|
public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
|
||||||
|
executeMethodAsync(() -> {
|
||||||
ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
|
ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
|
||||||
otherSession.setServiceImpl(transferToSession);
|
otherSession.setServiceImpl(transferToSession);
|
||||||
ImsCallSessionImplBase.this.transfer(otherSession);
|
ImsCallSessionImplBase.this.transfer(otherSession);
|
||||||
|
}, "consultativeTransfer");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void terminate(int reason) {
|
public void terminate(int reason) {
|
||||||
ImsCallSessionImplBase.this.terminate(reason);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hold(ImsStreamMediaProfile profile) {
|
public void hold(ImsStreamMediaProfile profile) {
|
||||||
ImsCallSessionImplBase.this.hold(profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resume(ImsStreamMediaProfile profile) {
|
public void resume(ImsStreamMediaProfile profile) {
|
||||||
ImsCallSessionImplBase.this.resume(profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void merge() {
|
public void merge() {
|
||||||
ImsCallSessionImplBase.this.merge();
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(int callType, ImsStreamMediaProfile profile) {
|
public void update(int callType, ImsStreamMediaProfile profile) {
|
||||||
ImsCallSessionImplBase.this.update(callType, profile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile),
|
||||||
|
"update");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void extendToConference(String[] participants) {
|
public void extendToConference(String[] participants) {
|
||||||
ImsCallSessionImplBase.this.extendToConference(participants);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants),
|
||||||
|
"extendToConference");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inviteParticipants(String[] participants) {
|
public void inviteParticipants(String[] participants) {
|
||||||
ImsCallSessionImplBase.this.inviteParticipants(participants);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants),
|
||||||
|
"inviteParticipants");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeParticipants(String[] participants) {
|
public void removeParticipants(String[] participants) {
|
||||||
ImsCallSessionImplBase.this.removeParticipants(participants);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants),
|
||||||
|
"removeParticipants");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendDtmf(char c, Message result) {
|
public void sendDtmf(char c, Message result) {
|
||||||
ImsCallSessionImplBase.this.sendDtmf(c, result);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startDtmf(char c) {
|
public void startDtmf(char c) {
|
||||||
ImsCallSessionImplBase.this.startDtmf(c);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopDtmf() {
|
public void stopDtmf() {
|
||||||
ImsCallSessionImplBase.this.stopDtmf();
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendUssd(String ussdMessage) {
|
public void sendUssd(String ussdMessage) {
|
||||||
ImsCallSessionImplBase.this.sendUssd(ussdMessage);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IImsVideoCallProvider getVideoCallProvider() {
|
public IImsVideoCallProvider getVideoCallProvider() {
|
||||||
return ImsCallSessionImplBase.this.getVideoCallProvider();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
|
||||||
|
.getVideoCallProvider(), "getVideoCallProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMultiparty() {
|
public boolean isMultiparty() {
|
||||||
return ImsCallSessionImplBase.this.isMultiparty();
|
return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(),
|
||||||
|
"isMultiparty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendRttModifyRequest(ImsCallProfile toProfile) {
|
public void sendRttModifyRequest(ImsCallProfile toProfile) {
|
||||||
ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile),
|
||||||
|
"sendRttModifyRequest");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendRttModifyResponse(boolean status) {
|
public void sendRttModifyResponse(boolean status) {
|
||||||
ImsCallSessionImplBase.this.sendRttModifyResponse(status);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status),
|
||||||
|
"sendRttModifyResponse");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendRttMessage(String rttMessage) {
|
public void sendRttMessage(String rttMessage) {
|
||||||
ImsCallSessionImplBase.this.sendRttMessage(rttMessage);
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage),
|
||||||
|
"sendRttMessage");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
|
public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
|
||||||
ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
|
executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
|
||||||
new ArraySet<RtpHeaderExtension>(extensions));
|
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) {
|
public void setServiceImpl(IImsCallSession serviceImpl) {
|
||||||
mServiceImpl = 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.ims.ImsConfig;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
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
|
* Controls the modification of IMS specific configurations. For more information on the supported
|
||||||
@@ -81,21 +90,48 @@ public class ImsConfigImplBase {
|
|||||||
WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
|
WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
|
||||||
private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
|
private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
|
||||||
private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
|
private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
private Executor mExecutor;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) {
|
public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Executor executor) {
|
||||||
|
mExecutor = executor;
|
||||||
mImsConfigImplBaseWeakReference =
|
mImsConfigImplBaseWeakReference =
|
||||||
new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
|
new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().addImsConfigCallback(c);
|
getImsConfigImpl().addImsConfigCallback(c);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "addImsConfigCallback");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception addImsConfigCallback");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().removeImsConfigCallback(c);
|
getImsConfigImpl().removeImsConfigCallback(c);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "removeImsConfigCallback");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception removeImsConfigCallback");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,17 +144,35 @@ public class ImsConfigImplBase {
|
|||||||
* unavailable.
|
* unavailable.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized int getConfigInt(int item) throws RemoteException {
|
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)) {
|
if (mProvisionedIntValue.containsKey(item)) {
|
||||||
return mProvisionedIntValue.get(item);
|
return mProvisionedIntValue.get(item);
|
||||||
} else {
|
} else {
|
||||||
int retVal = getImsConfigImpl().getConfigInt(item);
|
try {
|
||||||
if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
|
returnVal = getImsConfigImpl().getConfigInt(item);
|
||||||
updateCachedValue(item, retVal, false);
|
if (returnVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
|
||||||
|
mProvisionedIntValue.put(item, returnVal);
|
||||||
}
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnVal;
|
||||||
|
}, "getConfigInt");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value for ims service/capabilities parameters. It first checks its local cache,
|
* Gets the value for ims service/capabilities parameters. It first checks its local cache,
|
||||||
@@ -129,17 +183,35 @@ public class ImsConfigImplBase {
|
|||||||
* @return value in String format.
|
* @return value in String format.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized String getConfigString(int item) throws RemoteException {
|
public String getConfigString(int item) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
String retVal = executeMethodAsyncForResult(()-> {
|
||||||
|
String returnVal = null;
|
||||||
|
synchronized (mLock) {
|
||||||
if (mProvisionedStringValue.containsKey(item)) {
|
if (mProvisionedStringValue.containsKey(item)) {
|
||||||
return mProvisionedStringValue.get(item);
|
returnVal = mProvisionedStringValue.get(item);
|
||||||
} else {
|
} else {
|
||||||
String retVal = getImsConfigImpl().getConfigString(item);
|
try {
|
||||||
if (retVal != null) {
|
returnVal = getImsConfigImpl().getConfigString(item);
|
||||||
updateCachedValue(item, retVal, false);
|
if (returnVal != null) {
|
||||||
|
mProvisionedStringValue.put(item, returnVal);
|
||||||
}
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnVal;
|
||||||
|
}, "getConfigString");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value for IMS service/capabilities parameters by the operator device
|
* Sets the value for IMS service/capabilities parameters by the operator device
|
||||||
@@ -153,14 +225,32 @@ public class ImsConfigImplBase {
|
|||||||
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized int setConfigInt(int item, int value) throws RemoteException {
|
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);
|
mProvisionedIntValue.remove(item);
|
||||||
int retVal = getImsConfigImpl().setConfig(item, value);
|
returnVal = getImsConfigImpl().setConfig(item, value);
|
||||||
if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||||
updateCachedValue(item, value, true);
|
mProvisionedIntValue.put(item, value);
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "Set provision value of " + item +
|
Log.d(TAG, "Set provision value of " + item
|
||||||
" to " + value + " failed with error code " + retVal);
|
+ " 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;
|
return retVal;
|
||||||
@@ -178,12 +268,30 @@ public class ImsConfigImplBase {
|
|||||||
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
* {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized int setConfigString(int item, String value)
|
public int setConfigString(int item, String value)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
int retVal = executeMethodAsyncForResult(()-> {
|
||||||
|
int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
|
||||||
|
try {
|
||||||
|
synchronized (mLock) {
|
||||||
mProvisionedStringValue.remove(item);
|
mProvisionedStringValue.remove(item);
|
||||||
int retVal = getImsConfigImpl().setConfig(item, value);
|
returnVal = getImsConfigImpl().setConfig(item, value);
|
||||||
if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
|
||||||
updateCachedValue(item, value, true);
|
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;
|
return retVal;
|
||||||
@@ -191,7 +299,19 @@ public class ImsConfigImplBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
|
public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().updateImsCarrierConfigs(bundle);
|
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 {
|
private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
|
||||||
@@ -206,13 +326,37 @@ public class ImsConfigImplBase {
|
|||||||
@Override
|
@Override
|
||||||
public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed)
|
public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
|
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
|
@Override
|
||||||
public void notifyRcsAutoConfigurationRemoved()
|
public void notifyRcsAutoConfigurationRemoved()
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
|
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 {
|
private void notifyImsConfigChanged(int item, int value) throws RemoteException {
|
||||||
@@ -223,50 +367,144 @@ public class ImsConfigImplBase {
|
|||||||
getImsConfigImpl().notifyConfigChanged(item, value);
|
getImsConfigImpl().notifyConfigChanged(item, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void updateCachedValue(int item, int value, boolean notifyChange)
|
protected void updateCachedValue(int item, int value) {
|
||||||
throws RemoteException {
|
synchronized (mLock) {
|
||||||
mProvisionedIntValue.put(item, value);
|
mProvisionedIntValue.put(item, value);
|
||||||
if (notifyChange) {
|
|
||||||
notifyImsConfigChanged(item, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void updateCachedValue(int item, String value,
|
protected void updateCachedValue(int item, String value) {
|
||||||
boolean notifyChange) throws RemoteException {
|
synchronized (mLock) {
|
||||||
mProvisionedStringValue.put(item, value);
|
mProvisionedStringValue.put(item, value);
|
||||||
if (notifyChange) {
|
|
||||||
notifyImsConfigChanged(item, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().addRcsConfigCallback(c);
|
getImsConfigImpl().addRcsConfigCallback(c);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "addRcsConfigCallback");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception addRcsConfigCallback");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().removeRcsConfigCallback(c);
|
getImsConfigImpl().removeRcsConfigCallback(c);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "removeRcsConfigCallback");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception removeRcsConfigCallback");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void triggerRcsReconfiguration() throws RemoteException {
|
public void triggerRcsReconfiguration() throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().triggerAutoConfiguration();
|
getImsConfigImpl().triggerAutoConfiguration();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "triggerRcsReconfiguration");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception triggerRcsReconfiguration");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
|
public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
getImsConfigImpl().setRcsClientConfiguration(rcc);
|
getImsConfigImpl().setRcsClientConfiguration(rcc);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "setRcsClientConfiguration");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception setRcsClientConfiguration");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
|
public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
notifyImsConfigChanged(item, value);
|
notifyImsConfigChanged(item, value);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "notifyIntImsConfigChanged");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
Log.d(TAG, "ImsConfigImplBase Exception notifyIntImsConfigChanged");
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
|
public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(()-> {
|
||||||
|
try {
|
||||||
notifyImsConfigChanged(item, value);
|
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;
|
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
|
* @hide
|
||||||
*/
|
*/
|
||||||
public ImsConfigImplBase(Context context) {
|
public ImsConfigImplBase(@NonNull Context context) {
|
||||||
mImsConfigStub = new ImsConfigStub(this);
|
mImsConfigStub = new ImsConfigStub(this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImsConfigImplBase() {
|
public ImsConfigImplBase() {
|
||||||
mImsConfigStub = new ImsConfigStub(this);
|
mImsConfigStub = new ImsConfigStub(this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -427,8 +674,10 @@ public class ImsConfigImplBase {
|
|||||||
* @param value in Integer format.
|
* @param value in Integer format.
|
||||||
*/
|
*/
|
||||||
public final void notifyProvisionedValueChanged(int item, int value) {
|
public final void notifyProvisionedValueChanged(int item, int value) {
|
||||||
|
mImsConfigStub.updateCachedValue(item, value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mImsConfigStub.updateCachedValue(item, value, true);
|
mImsConfigStub.notifyImsConfigChanged(item, value);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead.");
|
Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead.");
|
||||||
}
|
}
|
||||||
@@ -443,8 +692,10 @@ public class ImsConfigImplBase {
|
|||||||
* @param value in String format.
|
* @param value in String format.
|
||||||
*/
|
*/
|
||||||
public final void notifyProvisionedValueChanged(int item, String value) {
|
public final void notifyProvisionedValueChanged(int item, String value) {
|
||||||
|
mImsConfigStub.updateCachedValue(item, value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mImsConfigStub.updateCachedValue(item, value, true);
|
mImsConfigStub.notifyImsConfigChanged(item, value);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead.");
|
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;
|
package android.telephony.ims.stub;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.ims.internal.IImsEcbm;
|
import com.android.ims.internal.IImsEcbm;
|
||||||
import com.android.ims.internal.IImsEcbmListener;
|
import com.android.ims.internal.IImsEcbmListener;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.util.Objects;
|
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
|
* 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 final Object mLock = new Object();
|
||||||
private IImsEcbmListener mListener;
|
private IImsEcbmListener mListener;
|
||||||
|
private Executor mExecutor = Runnable::run;
|
||||||
|
|
||||||
private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
|
private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void setListener(IImsEcbmListener listener) {
|
public void setListener(IImsEcbmListener listener) {
|
||||||
synchronized (mLock) {
|
executeMethodAsync(() -> {
|
||||||
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
||||||
Log.w(TAG, "setListener: discarding dead Binder");
|
Log.w(TAG, "setListener: discarding dead Binder");
|
||||||
mListener = null;
|
mListener = null;
|
||||||
@@ -62,12 +71,25 @@ public class ImsEcbmImplBase {
|
|||||||
+ "listener");
|
+ "listener");
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
}
|
}, "setListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exitEmergencyCallbackMode() {
|
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;
|
package android.telephony.ims.stub;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.telephony.ims.ImsExternalCallState;
|
import android.telephony.ims.ImsExternalCallState;
|
||||||
@@ -23,9 +24,14 @@ import android.util.Log;
|
|||||||
|
|
||||||
import com.android.ims.internal.IImsExternalCallStateListener;
|
import com.android.ims.internal.IImsExternalCallStateListener;
|
||||||
import com.android.ims.internal.IImsMultiEndpoint;
|
import com.android.ims.internal.IImsMultiEndpoint;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
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
|
* Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
|
||||||
@@ -43,11 +49,13 @@ public class ImsMultiEndpointImplBase {
|
|||||||
|
|
||||||
private IImsExternalCallStateListener mListener;
|
private IImsExternalCallStateListener mListener;
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
|
private Executor mExecutor = Runnable::run;
|
||||||
|
|
||||||
private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
|
private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
|
public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
|
||||||
synchronized (mLock) {
|
executeMethodAsync(() -> {
|
||||||
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
if (mListener != null && !mListener.asBinder().isBinderAlive()) {
|
||||||
Log.w(TAG, "setListener: discarding dead Binder");
|
Log.w(TAG, "setListener: discarding dead Binder");
|
||||||
mListener = null;
|
mListener = null;
|
||||||
@@ -67,12 +75,25 @@ public class ImsMultiEndpointImplBase {
|
|||||||
+ "listener");
|
+ "listener");
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
}
|
}, "setListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestImsExternalCallStateInfo() throws RemoteException {
|
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() {
|
public void requestImsExternalCallStateInfo() {
|
||||||
Log.d(TAG, "requestImsExternalCallStateInfo() not implemented");
|
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 android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
import com.android.internal.telephony.util.RemoteCallbackListExt;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
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
|
* Controls IMS registration for this ImsService and notifies the framework when the IMS
|
||||||
@@ -92,39 +101,114 @@ public class ImsRegistrationImplBase {
|
|||||||
// yet.
|
// yet.
|
||||||
private static final int REGISTRATION_STATE_UNKNOWN = -1;
|
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() {
|
private final IImsRegistration mBinder = new IImsRegistration.Stub() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
|
public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
|
||||||
synchronized (mLock) {
|
return executeMethodAsyncForResult(() -> (mRegistrationAttributes == null)
|
||||||
return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
|
? REGISTRATION_TECH_NONE : mRegistrationAttributes.getRegistrationTechnology(),
|
||||||
: mRegistrationAttributes.getRegistrationTechnology();
|
"getRegistrationTechnology");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
||||||
|
AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
|
||||||
|
executeMethodAsync(() -> {
|
||||||
|
try {
|
||||||
ImsRegistrationImplBase.this.addRegistrationCallback(c);
|
ImsRegistrationImplBase.this.addRegistrationCallback(c);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
exceptionRef.set(e);
|
||||||
|
}
|
||||||
|
}, "addRegistrationCallback");
|
||||||
|
|
||||||
|
if (exceptionRef.get() != null) {
|
||||||
|
throw exceptionRef.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
|
||||||
ImsRegistrationImplBase.this.removeRegistrationCallback(c);
|
executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c),
|
||||||
|
"removeRegistrationCallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void triggerFullNetworkRegistration(int sipCode, String sipReason) {
|
public void triggerFullNetworkRegistration(int sipCode, String sipReason) {
|
||||||
ImsRegistrationImplBase.this.triggerFullNetworkRegistration(sipCode, sipReason);
|
executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
|
||||||
|
.triggerFullNetworkRegistration(sipCode, sipReason),
|
||||||
|
"triggerFullNetworkRegistration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void triggerUpdateSipDelegateRegistration() {
|
public void triggerUpdateSipDelegateRegistration() {
|
||||||
ImsRegistrationImplBase.this.updateSipDelegateRegistration();
|
executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
|
||||||
|
.updateSipDelegateRegistration(), "triggerUpdateSipDelegateRegistration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void triggerSipDelegateDeregistration() {
|
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);
|
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.IImsUt;
|
||||||
import com.android.ims.internal.IImsUtListener;
|
import com.android.ims.internal.IImsUtListener;
|
||||||
|
import com.android.internal.telephony.util.TelephonyUtils;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Objects;
|
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
|
* 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;
|
public static final int INVALID_RESULT = -1;
|
||||||
|
|
||||||
|
private Executor mExecutor = Runnable::run;
|
||||||
|
|
||||||
private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
|
private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
private ImsUtListener mUtListener;
|
private ImsUtListener mUtListener;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws RemoteException {
|
public void close() throws RemoteException {
|
||||||
ImsUtImplBase.this.close();
|
executeMethodAsync(() ->ImsUtImplBase.this.close(), "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCallBarring(int cbType) throws RemoteException {
|
public int queryCallBarring(int cbType) throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCallBarring(cbType);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallBarring(cbType),
|
||||||
|
"queryCallBarring");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCallForward(int condition, String number) throws RemoteException {
|
public int queryCallForward(int condition, String number) throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCallForward(condition, number);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallForward(
|
||||||
|
condition, number), "queryCallForward");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCallWaiting() throws RemoteException {
|
public int queryCallWaiting() throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCallWaiting();
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallWaiting(),
|
||||||
|
"queryCallWaiting");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCLIR() throws RemoteException {
|
public int queryCLIR() throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCLIR();
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIR(), "queryCLIR");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCLIP() throws RemoteException {
|
public int queryCLIP() throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCLIP();
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIP(), "queryCLIP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCOLR() throws RemoteException {
|
public int queryCOLR() throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCOLR();
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLR(), "queryCOLR");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCOLP() throws RemoteException {
|
public int queryCOLP() throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCOLP();
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLP(), "queryCOLP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int transact(Bundle ssInfo) throws RemoteException {
|
public int transact(Bundle ssInfo) throws RemoteException {
|
||||||
return ImsUtImplBase.this.transact(ssInfo);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.transact(ssInfo),
|
||||||
|
"transact");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCallBarring(int cbType, int action, String[] barrList) throws
|
public int updateCallBarring(int cbType, int action, String[] barrList) throws
|
||||||
RemoteException {
|
RemoteException {
|
||||||
return ImsUtImplBase.this.updateCallBarring(cbType, action, barrList);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallBarring(
|
||||||
|
cbType, action, barrList), "updateCallBarring");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCallForward(int action, int condition, String number, int serviceClass,
|
public int updateCallForward(int action, int condition, String number, int serviceClass,
|
||||||
int timeSeconds) throws RemoteException {
|
int timeSeconds) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCallForward(action, condition, number, serviceClass,
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallForward(
|
||||||
timeSeconds);
|
action, condition, number, serviceClass, timeSeconds), "updateCallForward");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
|
public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCallWaiting(enable, serviceClass);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallWaiting(
|
||||||
|
enable, serviceClass), "updateCallWaiting");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCLIR(int clirMode) throws RemoteException {
|
public int updateCLIR(int clirMode) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCLIR(clirMode);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIR(clirMode),
|
||||||
|
"updateCLIR");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCLIP(boolean enable) throws RemoteException {
|
public int updateCLIP(boolean enable) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCLIP(enable);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIP(enable),
|
||||||
|
"updateCLIP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCOLR(int presentation) throws RemoteException {
|
public int updateCOLR(int presentation) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCOLR(presentation);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLR(presentation),
|
||||||
|
"updateCOLR");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCOLP(boolean enable) throws RemoteException {
|
public int updateCOLP(boolean enable) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCOLP(enable);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLP(enable),
|
||||||
|
"updateCOLP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setListener(IImsUtListener listener) throws RemoteException {
|
public void setListener(IImsUtListener listener) throws RemoteException {
|
||||||
synchronized (mLock) {
|
executeMethodAsync(() -> {
|
||||||
if (mUtListener != null
|
if (mUtListener != null
|
||||||
&& !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
|
&& !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
|
||||||
Log.w(TAG, "setListener: discarding dead Binder");
|
Log.w(TAG, "setListener: discarding dead Binder");
|
||||||
@@ -229,29 +248,59 @@ public class ImsUtImplBase {
|
|||||||
+ "listener");
|
+ "listener");
|
||||||
mUtListener = new ImsUtListener(listener);
|
mUtListener = new ImsUtListener(listener);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ImsUtImplBase.this.setListener(mUtListener);
|
ImsUtImplBase.this.setListener(mUtListener);
|
||||||
|
}, "setListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int queryCallBarringForServiceClass(int cbType, int serviceClass)
|
public int queryCallBarringForServiceClass(int cbType, int serviceClass)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
return ImsUtImplBase.this.queryCallBarringForServiceClass(cbType, serviceClass);
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||||
|
.queryCallBarringForServiceClass(cbType, serviceClass),
|
||||||
|
"queryCallBarringForServiceClass");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCallBarringForServiceClass(int cbType, int action,
|
public int updateCallBarringForServiceClass(int cbType, int action,
|
||||||
String[] barrList, int serviceClass) throws RemoteException {
|
String[] barrList, int serviceClass) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCallBarringForServiceClass(
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||||
cbType, action, barrList, serviceClass);
|
.updateCallBarringForServiceClass(cbType, action, barrList, serviceClass),
|
||||||
|
"updateCallBarringForServiceClass");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
|
public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
|
||||||
int serviceClass, String password) throws RemoteException {
|
int serviceClass, String password) throws RemoteException {
|
||||||
return ImsUtImplBase.this.updateCallBarringWithPassword(
|
return executeMethodAsyncForResult(() -> ImsUtImplBase.this
|
||||||
cbType, action, barrList, serviceClass, password);
|
.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() {
|
public IImsUt getInterface() {
|
||||||
return mServiceImpl;
|
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<>();
|
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.
|
* Create an implementation of SipTransportImplBase.
|
||||||
*
|
*
|
||||||
@@ -212,4 +223,16 @@ public class SipTransportImplBase {
|
|||||||
public ISipTransport getBinder() {
|
public ISipTransport getBinder() {
|
||||||
return mSipTransportImpl;
|
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