Merge "Modify RCS UCE APIs to use AIDL Interfaces."

This commit is contained in:
Brad Ebinger
2019-08-13 22:46:18 +00:00
committed by Gerrit Code Review
10 changed files with 514 additions and 149 deletions

View File

@@ -508,6 +508,7 @@ java_defaults {
"telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl",
"telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",

View File

@@ -39,11 +39,11 @@ public final class ImsException extends Exception {
*/
public static final int CODE_ERROR_UNSPECIFIED = 0;
/**
* The operation has failed because there is no {@link ImsService} available to service it. This
* may be due to an {@link ImsService} crash or other illegal state.
* The operation has failed because there is no remote process available to service it. This
* may be due to a process crash or other illegal state.
* <p>
* This is a temporary error and the operation may be retried until the connection to the
* {@link ImsService} is restored.
* remote process is restored.
*/
public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1;

View File

@@ -16,10 +16,38 @@
package android.telephony.ims.aidl;
import android.net.Uri;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IRcsFeatureListener;
import android.telephony.ims.feature.CapabilityChangeRequest;
import java.util.List;
/**
* See RcsFeature for more information.
* {@hide}
*/
interface IImsRcsFeature {
//Empty Default Implementation
// Not oneway because we need to verify this completes before doing anything else.
void setListener(IRcsFeatureListener listener);
int queryCapabilityStatus();
// Inherited from ImsFeature
int getFeatureState();
oneway void addCapabilityCallback(IImsCapabilityCallback c);
oneway void removeCapabilityCallback(IImsCapabilityCallback c);
oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest r,
IImsCapabilityCallback c);
oneway void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c);
// RcsPresenceExchangeImplBase specific api
oneway void requestCapabilities(in List<Uri> uris, int operationToken);
oneway void updateCapabilities(in RcsContactUceCapability capabilities, int operationToken);
// RcsSipOptionsImplBase specific api
oneway void sendCapabilityRequest(in Uri contactUri,
in RcsContactUceCapability capabilities, int operationToken);
oneway void respondToCapabilityRequest(in String contactUri,
in RcsContactUceCapability ownCapabilities, int operationToken);
oneway void respondToCapabilityRequestWithError(in Uri contactUri, int code, in String reason,
int operationToken);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.telephony.ims.aidl;
import android.net.Uri;
import android.telephony.ims.RcsContactUceCapability;
import java.util.List;
/**
* Listener interface for updates from the RcsFeature back to the framework.
* {@hide}
*/
interface IRcsFeatureListener {
//RcsCapabilityExchange specific
oneway void onCommandUpdate(int commandCode, int operationToken);
// RcsPresenceExchangeImplBase Specific
oneway void onNetworkResponse(int code, in String reason, int operationToken);
oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos,
int operationToken);
oneway void onNotifyUpdateCapabilities();
oneway void onUnpublish();
// RcsSipOptionsImplBase specific
oneway void onCapabilityRequestResponseOptions(int code, in String reason,
in RcsContactUceCapability info, int operationToken);
oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo,
int operationToken);
}

View File

@@ -33,12 +33,8 @@ import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Base class for all IMS features that are supported by the framework. Use a concrete subclass
@@ -51,35 +47,6 @@ public abstract class ImsFeature {
private static final String LOG_TAG = "ImsFeature";
/**
* Action to broadcast when ImsService is up.
* Internal use only.
* Only defined here separately for compatibility purposes with the old ImsService.
*
* @hide
*/
public static final String ACTION_IMS_SERVICE_UP =
"com.android.ims.IMS_SERVICE_UP";
/**
* Action to broadcast when ImsService is down.
* Internal use only.
* Only defined here separately for compatibility purposes with the old ImsService.
*
* @hide
*/
public static final String ACTION_IMS_SERVICE_DOWN =
"com.android.ims.IMS_SERVICE_DOWN";
/**
* Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
* A long value; the phone ID corresponding to the IMS service coming up or down.
* Only defined here separately for compatibility purposes with the old ImsService.
*
* @hide
*/
public static final String EXTRA_PHONE_ID = "android:phone_id";
/**
* Invalid feature value
* @hide
@@ -335,8 +302,8 @@ public abstract class ImsFeature {
/** @hide */
protected final Object mLock = new Object();
private final Set<IImsFeatureStatusCallback> mStatusCallbacks =
Collections.newSetFromMap(new WeakHashMap<>());
private final RemoteCallbackList<IImsFeatureStatusCallback> mStatusCallbacks =
new RemoteCallbackList<>();
private @ImsState int mState = STATE_UNAVAILABLE;
private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks =
@@ -397,9 +364,7 @@ public abstract class ImsFeature {
// If we have just connected, send queued status.
c.notifyImsFeatureStatus(getFeatureState());
// Add the callback if the callback completes successfully without a RemoteException.
synchronized (mLock) {
mStatusCallbacks.add(c);
}
mStatusCallbacks.register(c);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
@@ -411,29 +376,21 @@ public abstract class ImsFeature {
*/
@VisibleForTesting
public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) {
synchronized (mLock) {
mStatusCallbacks.remove(c);
}
mStatusCallbacks.unregister(c);
}
/**
* Internal method called by ImsFeature when setFeatureState has changed.
*/
private void notifyFeatureState(@ImsState int state) {
synchronized (mLock) {
for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator();
iter.hasNext(); ) {
IImsFeatureStatusCallback callback = iter.next();
try {
Log.i(LOG_TAG, "notifying ImsFeatureState=" + state);
callback.notifyImsFeatureStatus(state);
} catch (RemoteException e) {
// remove if the callback is no longer alive.
iter.remove();
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
mStatusCallbacks.broadcast((c) -> {
try {
c.notifyImsFeatureStatus(state);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping "
+ "callback.");
}
}
});
}
/**
@@ -452,10 +409,23 @@ public abstract class ImsFeature {
/**
* @hide
*/
public final void removeCapabilityCallback(IImsCapabilityCallback c) {
final void removeCapabilityCallback(IImsCapabilityCallback c) {
mCapabilityCallbacks.unregister(c);
}
/**@hide*/
final void queryCapabilityConfigurationInternal(int capability, int radioTech,
IImsCapabilityCallback c) {
boolean enabled = queryCapabilityConfiguration(capability, radioTech);
try {
if (c != null) {
c.onQueryCapabilityConfiguration(capability, radioTech, enabled);
}
} catch (RemoteException e) {
Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!");
}
}
/**
* @return the cached capabilities status for this feature.
* @hide
@@ -484,30 +454,35 @@ public abstract class ImsFeature {
/**
* Called by the ImsFeature when the capabilities status has changed.
*
* @param c A {@link Capabilities} containing the new Capabilities status.
* @param caps the new {@link Capabilities} status of the {@link ImsFeature}.
*
* @hide
*/
protected final void notifyCapabilitiesStatusChanged(Capabilities c) {
protected final void notifyCapabilitiesStatusChanged(Capabilities caps) {
synchronized (mLock) {
mCapabilityStatus = c.copy();
mCapabilityStatus = caps.copy();
}
int count = mCapabilityCallbacks.beginBroadcast();
try {
for (int i = 0; i < count; i++) {
try {
mCapabilityCallbacks.getBroadcastItem(i).onCapabilitiesStatusChanged(
c.mCapabilities);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + " " + "notifyCapabilitiesStatusChanged() - Skipping " +
"callback.");
}
mCapabilityCallbacks.broadcast((callback) -> {
try {
callback.onCapabilitiesStatusChanged(caps.mCapabilities);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping "
+ "callback.");
}
} finally {
mCapabilityCallbacks.finishBroadcast();
}
});
}
/**
* Provides the ImsFeature with the ability to return the framework Capability Configuration
* for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and
* includes a capability A to enable or disable, this method should return the correct enabled
* status for capability A.
* @param capability The capability that we are querying the configuration for.
* @return true if the capability is enabled, false otherwise.
* @hide
*/
public abstract boolean queryCapabilityConfiguration(int capability, int radioTech);
/**
* Features should override this method to receive Capability preference change requests from
* the framework using the provided {@link CapabilityChangeRequest}. If any of the capabilities

View File

@@ -37,7 +37,6 @@ import android.telephony.ims.stub.ImsMultiEndpointImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsEcbm;
@@ -154,17 +153,13 @@ public class MmTelFeature extends ImsFeature {
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
IImsCapabilityCallback c) {
synchronized (mLock) {
MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
}
MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
}
@Override
public void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c) {
synchronized (mLock) {
queryCapabilityConfigurationInternal(capability, radioTech, c);
}
queryCapabilityConfigurationInternal(capability, radioTech, c);
}
@Override
@@ -381,18 +376,6 @@ public class MmTelFeature extends ImsFeature {
}
}
private void queryCapabilityConfigurationInternal(int capability, int radioTech,
IImsCapabilityCallback c) {
boolean enabled = queryCapabilityConfiguration(capability, radioTech);
try {
if (c != null) {
c.onQueryCapabilityConfiguration(capability, radioTech, enabled);
}
} catch (RemoteException e) {
Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!");
}
}
/**
* The current capability status that this MmTelFeature has defined is available. This
* configuration will be used by the platform to figure out which capabilities are CURRENTLY
@@ -512,6 +495,7 @@ public class MmTelFeature extends ImsFeature {
* @param capability The capability that we are querying the configuration for.
* @return true if the capability is enabled, false otherwise.
*/
@Override
public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base implementation - Override to provide functionality

View File

@@ -16,14 +16,32 @@
package android.telephony.ims.feature;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IRcsFeatureListener;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
import android.telephony.ims.stub.RcsSipOptionsImplBase;
import android.util.Log;
import com.android.internal.util.FunctionalUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
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;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -33,10 +51,132 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class RcsFeature extends ImsFeature {
/**{@inheritDoc}*/
private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() {
// Empty Default Implementation.
};
private static final String LOG_TAG = "RcsFeature";
private static final class RcsFeatureBinder extends IImsRcsFeature.Stub {
// Reference the outer class in order to have better test coverage metrics instead of
// creating a inner class referencing the outer class directly.
private final RcsFeature mReference;
private final Executor mExecutor;
RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
mReference = classRef;
mExecutor = executor;
}
@Override
public void setListener(IRcsFeatureListener listener) {
mReference.setListener(listener);
}
@Override
public int queryCapabilityStatus() throws RemoteException {
return executeMethodAsyncForResult(
() -> mReference.queryCapabilityStatus().mCapabilities,
"queryCapabilityStatus");
}
@Override
public void addCapabilityCallback(IImsCapabilityCallback c) throws RemoteException {
executeMethodAsync(() -> mReference.addCapabilityCallback(c), "addCapabilityCallback");
}
@Override
public void removeCapabilityCallback(IImsCapabilityCallback c) throws RemoteException {
executeMethodAsync(() -> mReference.removeCapabilityCallback(c),
"removeCapabilityCallback");
}
@Override
public void changeCapabilitiesConfiguration(CapabilityChangeRequest r,
IImsCapabilityCallback c) throws RemoteException {
executeMethodAsync(() -> mReference.requestChangeEnabledCapabilities(r, c),
"changeCapabilitiesConfiguration");
}
@Override
public void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c) throws RemoteException {
executeMethodAsync(() -> mReference.queryCapabilityConfigurationInternal(capability,
radioTech, c), "queryCapabilityConfiguration");
}
@Override
public int getFeatureState() throws RemoteException {
return executeMethodAsyncForResult(mReference::getFeatureState, "getFeatureState");
}
// RcsPresenceExchangeImplBase specific APIS
@Override
public void requestCapabilities(List<Uri> uris, int operationToken) throws RemoteException {
executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
.requestCapabilities(uris, operationToken), "requestCapabilities");
}
@Override
public void updateCapabilities(RcsContactUceCapability capabilities, int operationToken)
throws RemoteException {
executeMethodAsync(() -> mReference.getPresenceExchangeInternal()
.updateCapabilities(capabilities, operationToken),
"updateCapabilities");
}
// RcsSipOptionsImplBase specific APIS
@Override
public void sendCapabilityRequest(Uri contactUri, RcsContactUceCapability capabilities,
int operationToken) throws RemoteException {
executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
.sendCapabilityRequest(contactUri, capabilities, operationToken),
"sendCapabilityRequest");
}
@Override
public void respondToCapabilityRequest(String contactUri,
RcsContactUceCapability ownCapabilities, int operationToken)
throws RemoteException {
executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
.respondToCapabilityRequest(contactUri, ownCapabilities,
operationToken), "respondToCapabilityRequest");
}
@Override
public void respondToCapabilityRequestWithError(Uri contactUri, int code, String reason,
int operationToken) throws RemoteException {
executeMethodAsync(() -> mReference.getOptionsExchangeInternal()
.respondToCapabilityRequestWithError(contactUri, code, reason,
operationToken), "respondToCapabilityRequestWithError");
}
// Call the methods with a clean calling identity on the executor and wait indefinitely for
// the future to return.
private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName)
throws RemoteException {
// call with a clean calling identity on the executor and wait indefinitely for the
// future to return.
try {
CompletableFuture.runAsync(
() -> Binder.withCleanCallingIdentity(r), mExecutor).join();
} catch (CancellationException | CompletionException e) {
Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
+ e.getMessage());
throw new RemoteException(e.getMessage());
}
}
private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r,
String errorLogName) throws RemoteException {
// call with a clean calling identity on the executor and wait indefinitely for the
// future to return.
CompletableFuture<T> future = CompletableFuture.supplyAsync(
() -> Binder.withCleanCallingIdentity(r), mExecutor);
try {
return future.get();
} catch (ExecutionException | InterruptedException e) {
Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
+ e.getMessage());
throw new RemoteException(e.getMessage());
}
}
}
/**
* Contains the capabilities defined and supported by a {@link RcsFeature} in the
@@ -81,27 +221,66 @@ public class RcsFeature extends ImsFeature {
/**@hide*/
public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) {
super(capabilities);
}
/**@hide*/
private RcsImsCapabilities(Capabilities c) {
super(c.getMask());
}
/**@hide*/
@Override
public void addCapabilities(@RcsImsCapabilityFlag int capabilities) {
super.addCapabilities(capabilities);
}
/**@hide*/
@Override
public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) {
super.removeCapabilities(capabilities);
}
/**@hide*/
@Override
public boolean isCapable(@RcsImsCapabilityFlag int capabilities) {
return false;
return super.isCapable(capabilities);
}
}
private final RcsFeatureBinder mImsRcsBinder;
private IRcsFeatureListener mListenerBinder;
private RcsPresenceExchangeImplBase mPresExchange;
private RcsSipOptionsImplBase mSipOptions;
/**
* Create a new RcsFeature.
* <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 RcsFeature#RcsFeature(Executor)} instead.
*/
public RcsFeature() {
super();
// Run on the Binder threads that call them.
mImsRcsBinder = new RcsFeatureBinder(this, Runnable::run);
}
/**
* Create a new RcsFeature using the Executor specified for methods being called by the
* framework.
* @param executor The executor for the framework to use when making calls to this service.
* @hide
*/
public RcsFeature(@NonNull Executor executor) {
super();
if (executor == null) {
throw new IllegalArgumentException("executor can not be null.");
}
// Run on the Binder thread by default.
mImsRcsBinder = new RcsFeatureBinder(this, executor);
}
/**
* Query the current {@link RcsImsCapabilities} status set by the RcsFeature. If a capability is
* set, the {@link RcsFeature} has brought up the capability and is ready for framework
@@ -111,7 +290,7 @@ public class RcsFeature extends ImsFeature {
*/
@Override
public final RcsImsCapabilities queryCapabilityStatus() {
throw new UnsupportedOperationException();
return new RcsImsCapabilities(super.queryCapabilityStatus());
}
/**
@@ -120,8 +299,11 @@ public class RcsFeature extends ImsFeature {
* Call {@link #queryCapabilityStatus()} to return the current capability status.
* @hide
*/
public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) {
throw new UnsupportedOperationException();
public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
if (c == null) {
throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
}
super.notifyCapabilitiesStatusChanged(c);
}
/**
@@ -133,8 +315,10 @@ public class RcsFeature extends ImsFeature {
* @hide
*/
public boolean queryCapabilityConfiguration(
@RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
throw new UnsupportedOperationException();
@RcsImsCapabilities.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base Implementation - Override to provide functionality
return false;
}
/**
* Called from the framework when the {@link RcsImsCapabilities} that have been configured for
@@ -155,7 +339,7 @@ public class RcsFeature extends ImsFeature {
@Override
public void changeEnabledCapabilities(CapabilityChangeRequest request,
CapabilityCallbackProxy c) {
throw new UnsupportedOperationException();
// Base Implementation - Override to provide functionality
}
/**
@@ -192,13 +376,6 @@ public class RcsFeature extends ImsFeature {
return new RcsPresenceExchangeImplBase();
}
/**
* Construct a new {@link RcsFeature} instance.
*/
public RcsFeature() {
super();
}
/**{@inheritDoc}*/
@Override
public void onFeatureRemoved() {
@@ -218,4 +395,40 @@ public class RcsFeature extends ImsFeature {
public final IImsRcsFeature getBinder() {
return mImsRcsBinder;
}
/**@hide*/
public IRcsFeatureListener getListener() {
synchronized (mLock) {
return mListenerBinder;
}
}
private void setListener(IRcsFeatureListener listener) {
synchronized (mLock) {
mListenerBinder = listener;
if (mListenerBinder != null) {
onFeatureReady();
}
}
}
private RcsPresenceExchangeImplBase getPresenceExchangeInternal() {
synchronized (mLock) {
if (mPresExchange == null) {
mPresExchange = getPresenceExchangeImpl();
mPresExchange.initialize(this);
}
return mPresExchange;
}
}
private RcsSipOptionsImplBase getOptionsExchangeInternal() {
synchronized (mLock) {
if (mSipOptions == null) {
mSipOptions = getOptionsExchangeImpl();
mSipOptions.initialize(this);
}
return mSipOptions;
}
}
}

View File

@@ -17,6 +17,11 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
import android.telephony.ims.aidl.IRcsFeatureListener;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,6 +77,24 @@ public class RcsCapabilityExchange {
})
public @interface CommandCode {}
private RcsFeature mFeature;
/** @hide */
public final void initialize(RcsFeature feature) {
mFeature = feature;
}
/** @hide */
protected final IRcsFeatureListener getListener() throws ImsException {
IRcsFeatureListener listener = mFeature.getListener();
if (listener == null) {
throw new ImsException("Connection to Framework has not been established, wait for "
+ "onFeatureReady().", ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
return mFeature.getListener();
}
/**
* Provides the framework with an update as to whether or not a command completed successfully
* locally. This includes capabilities requests and updates from the network. If it does not
@@ -82,8 +105,18 @@ public class RcsCapabilityExchange {
* @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
* updates will be sent for this command using the associated operationToken.
* @param operationToken the token associated with the pending command.
* @throws ImsException If this {@link RcsCapabilityExchange} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onCommandUpdate(@CommandCode int code, int operationToken) {
throw new UnsupportedOperationException();
public final void onCommandUpdate(@CommandCode int code, int operationToken)
throws ImsException {
try {
getListener().onCommandUpdate(code, operationToken);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
}

View File

@@ -19,7 +19,11 @@ package android.telephony.ims.stub;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -113,54 +117,95 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
* Provide the framework with a subsequent network response update to
* {@link #updateCapabilities(RcsContactUceCapability, int)} and
* {@link #requestCapabilities(List, int)} operations.
*
* @param code The SIP response code sent from the network for the operation token specified.
* @param reason The optional reason response from the network. If the network provided no
* reason with the code, the string should be empty.
* @param operationToken The token associated with the operation this service is providing a
* response for.
* @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
int operationToken) {
throw new UnsupportedOperationException();
int operationToken) throws ImsException {
try {
getListener().onNetworkResponse(code, reason, operationToken);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Provides the framework with the requested contacts capabilities requested by the framework
* using {@link #requestCapabilities(List, int)} .
* using {@link #requestCapabilities(List, int)}.
*
* @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos,
int operationToken) {
throw new UnsupportedOperationException();
int operationToken) throws ImsException {
try {
getListener().onCapabilityRequestResponsePresence(infos, operationToken);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Trigger the framework to provide a capability update using
* {@link #updateCapabilities(RcsContactUceCapability, int)}. This is typically used when trying
* to generate an initial PUBLISH for a new subscription to the network.
* {@link #updateCapabilities(RcsContactUceCapability, int)}.
* <p>
* The device will cache all presence publications after boot until this method is called once.
* This is typically used when trying to generate an initial PUBLISH for a new subscription to
* the network. The device will cache all presence publications after boot until this method is
* called once.
* @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onNotifyUpdateCapabilites() {
throw new UnsupportedOperationException();
public final void onNotifyUpdateCapabilites() throws ImsException {
try {
getListener().onNotifyUpdateCapabilities();
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Notify the framework that the devices capabilities have been unpublished from the network.
*
* @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onUnpublish() {
throw new UnsupportedOperationException();
public final void onUnpublish() throws ImsException {
try {
getListener().onUnpublish();
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* The user capabilities of one or multiple contacts have been requested.
* The user capabilities of one or multiple contacts have been requested by the framework.
* <p>
* This must be followed up with one call to {@link #onCommandUpdate(int, int)} with an update
* as to whether or not the command completed as well as subsequent network
* updates using {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
* {@link #onCapabilityRequestResponse(List, int)} should be called with
* the presence information for the contacts specified.
* @param uris A {@link List} of the URIs that the framework is requesting the UCE capabilities
* for.
* The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
* indicate whether or not this operation succeeded. If this operation succeeds, network
* response updates should be sent to the framework using
* {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
* {@link #onCapabilityRequestResponse(List, int)} should be called with the presence
* information for the contacts specified.
* @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
* capabilities for.
* @param operationToken The token associated with this operation. Updates to this request using
* {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
* {@link #onCapabilityRequestResponse(List, int)} must use the same operation token
@@ -169,14 +214,20 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "requestCapabilities called with no implementation.");
onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
try {
getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
} catch (RemoteException | ImsException e) {
// Do not do anything, this is a stub implementation.
}
}
/**
* The capabilities of this device have been updated and should be published
* to the network. The framework will expect one {@link #onCommandUpdate(int, int)} call to
* indicate whether or not this operation failed first as well as network response
* updates to this update using {@link #onNetworkResponse(int, String, int)}.
* The capabilities of this device have been updated and should be published to the network.
* <p>
* The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
* indicate whether or not this operation succeeded. If this operation succeeds, network
* response updates should be sent to the framework using
* {@link #onNetworkResponse(int, String, int)}.
* @param capabilities The capabilities for this device.
* @param operationToken The token associated with this operation. Any subsequent
* {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
@@ -186,6 +237,10 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
try {
getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
} catch (RemoteException | ImsException e) {
// Do not do anything, this is a stub implementation.
}
}
}

View File

@@ -20,7 +20,11 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -87,10 +91,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
* @param info the contact's UCE capabilities associated with the capability request.
* @param operationToken The token associated with the original capability request, set by
* {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
* @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
@Nullable RcsContactUceCapability info, int operationToken) {
throw new UnsupportedOperationException();
@Nullable RcsContactUceCapability info, int operationToken) throws ImsException {
try {
getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
@@ -104,10 +117,19 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
* @param operationToken An unique operation token that you have generated that will be returned
* by the framework in
* {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
* @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
@NonNull RcsContactUceCapability remoteInfo, int operationToken) {
throw new UnsupportedOperationException();
@NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException {
try {
getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
@@ -127,7 +149,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@NonNull RcsContactUceCapability capabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
try {
getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
} catch (RemoteException | ImsException e) {
// Do not do anything, this is a stub implementation.
}
}
/**
@@ -145,7 +171,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
try {
getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
} catch (RemoteException | ImsException e) {
// Do not do anything, this is a stub implementation.
}
}
/**
@@ -164,6 +194,10 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
@SipResponseCode int code, @NonNull String reason, int operationToken) {
// Stub - to be implemented by service
Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken);
try {
getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
} catch (RemoteException | ImsException e) {
// Do not do anything, this is a stub implementation.
}
}
}