diff options
10 files changed, 1456 insertions, 4 deletions
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java new file mode 100644 index 000000000000..3c343dd19a86 --- /dev/null +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -0,0 +1,234 @@ +/* + * 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; + +import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.os.Binder; +import android.telephony.SubscriptionManager; +import android.telephony.ims.aidl.IImsCapabilityCallback; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; + +import java.util.concurrent.Executor; + +/** + * Manager for interfacing with the framework RCS services, including the User Capability Exchange + * (UCE) service, as well as managing user settings. + * + * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager. + * @hide + */ +public class ImsRcsManager { + + /** + * Receives RCS availability status updates from the ImsService. + * + * @see #isAvailable(int) + * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback) + * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback) + */ + public static class AvailabilityCallback { + + private static class CapabilityBinder extends IImsCapabilityCallback.Stub { + + private final AvailabilityCallback mLocalCallback; + private Executor mExecutor; + + CapabilityBinder(AvailabilityCallback c) { + mLocalCallback = c; + } + + @Override + public void onCapabilitiesStatusChanged(int config) { + if (mLocalCallback == null) return; + + Binder.withCleanCallingIdentity(() -> + mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged( + new RcsFeature.RcsImsCapabilities(config)))); + } + + @Override + public void onQueryCapabilityConfiguration(int capability, int radioTech, + boolean isEnabled) { + // This is not used for public interfaces. + } + + @Override + public void onChangeCapabilityConfigurationError(int capability, int radioTech, + @ImsFeature.ImsCapabilityError int reason) { + // This is not used for public interfaces + } + + private void setExecutor(Executor executor) { + mExecutor = executor; + } + } + + private final CapabilityBinder mBinder = new CapabilityBinder(this); + + /** + * The availability of the feature's capabilities has changed to either available or + * unavailable. + * <p> + * If unavailable, the feature does not support the capability at the current time. This may + * be due to network or subscription provisioning changes, such as the IMS registration + * being lost, network type changing, or OMA-DM provisioning updates. + * + * @param capabilities The new availability of the capabilities. + */ + public void onAvailabilityChanged(RcsFeature.RcsImsCapabilities capabilities) { + } + + /**@hide*/ + public final IImsCapabilityCallback getBinder() { + return mBinder; + } + + private void setExecutor(Executor executor) { + mBinder.setExecutor(executor); + } + } + + private final int mSubId; + private final Context mContext; + + + /** + * Create an instance of ImsRcsManager for the subscription id specified. + * + * @param context The context to create this ImsRcsManager instance within. + * @param subscriptionId The ID of the subscription that this ImsRcsManager will use. + * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() + * @throws IllegalArgumentException if the subscription is invalid. + * @hide + */ + public static ImsRcsManager createForSubscriptionId(Context context, int subscriptionId) { + if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { + throw new IllegalArgumentException("Invalid subscription ID"); + } + + return new ImsRcsManager(context, subscriptionId); + } + + /** + * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this class. + */ + private ImsRcsManager(Context context, int subId) { + mContext = context; + mSubId = subId; + } + + /** + * Registers an {@link AvailabilityCallback} with the system, which will provide RCS + * availability updates for the subscription specified. + * + * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to + * subscription changed events and call + * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a + * subscription is removed. + * <p> + * When the callback is registered, it will initiate the callback c to be called with the + * current capabilities. + * + * @param executor The executor the callback events should be run on. + * @param c The RCS {@link AvailabilityCallback} to be registered. + * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback) + * @throws ImsException if the subscription associated with this instance of + * {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not + * available. This can happen if the ImsService has crashed, for example, or if the subscription + * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void registerRcsAvailabilityCallback(@CallbackExecutor Executor executor, + @NonNull AvailabilityCallback c) throws ImsException { + if (c == null) { + throw new IllegalArgumentException("Must include a non-null AvailabilityCallback."); + } + if (executor == null) { + throw new IllegalArgumentException("Must include a non-null Executor."); + } + c.setExecutor(executor); + throw new UnsupportedOperationException("registerRcsAvailabilityCallback is not" + + "supported."); + } + + /** + * Removes an existing RCS {@link AvailabilityCallback}. + * <p> + * When the subscription associated with this callback is removed (SIM removed, ESIM swap, + * etc...), this callback will automatically be unregistered. If this method is called for an + * inactive subscription, it will result in a no-op. + * @param c The RCS {@link AvailabilityCallback} to be removed. + * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback) + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c) { + if (c == null) { + throw new IllegalArgumentException("Must include a non-null AvailabilityCallback."); + } + throw new UnsupportedOperationException("unregisterRcsAvailabilityCallback is not" + + "supported."); + } + + /** + * Query for the capability of an IMS RCS service provided by the framework. + * <p> + * This only reports the status of RCS capabilities provided by the framework, not necessarily + * RCS capabilities provided over-the-top by applications. + * + * @param capability The RCS capability to query. + * @return true if the RCS capability is capable for this subscription, false otherwise. This + * does not necessarily mean that we are registered for IMS and the capability is available, but + * rather the subscription is capable of this service over IMS. + * @see #isAvailable(int) + * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { + throw new UnsupportedOperationException("isCapable is not supported."); + } + + /** + * Query the availability of an IMS RCS capability. + * <p> + * This only reports the status of RCS capabilities provided by the framework, not necessarily + * RCS capabilities provided by over-the-top by applications. + * + * @param capability the RCS capability to query. + * @return true if the RCS capability is currently available for the associated subscription, + * false otherwise. If the capability is available, IMS is registered and the service is + * currently available over IMS. + * @see #isCapable(int) + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) { + throw new UnsupportedOperationException("isAvailable is not supported."); + } + + /** + * @return A new {@link RcsUceAdapter} used for User Capability Exchange (UCE) operations for + * this subscription. + */ + @NonNull + public RcsUceAdapter getUceAdapter() { + return new RcsUceAdapter(mSubId); + } +} diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index cc037e3ea814..effdf48067c3 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -387,6 +387,24 @@ public class ProvisioningManager { } } + /** + * Notify the framework that an RCS autoconfiguration XML file has been received for + * provisioning. + * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. + * @param isCompressed The XML file is compressed in gzip format and must be decompressed + * before being read. + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { + if (config == null) { + throw new IllegalArgumentException("Must include a non-null config XML file."); + } + // TODO: Connect to ImsConfigImplBase. + throw new UnsupportedOperationException("notifyRcsAutoConfigurationReceived is not" + + "supported"); + } + private static boolean isImsAvailableOnDevice() { IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (pm == null) { diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl new file mode 100644 index 000000000000..bef6a4037fea --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.aidl @@ -0,0 +1,20 @@ +/* + * 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; + +parcelable RcsContactUceCapability; diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java new file mode 100644 index 000000000000..492170b1069a --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -0,0 +1,291 @@ +/* + * 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; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Contains the User Capability Exchange capabilities corresponding to a contact's URI. + * @hide + */ +public final class RcsContactUceCapability implements Parcelable { + + /** Supports 1-to-1 chat */ + public static final int CAPABILITY_CHAT_STANDALONE = (1 << 0); + /** Supports group chat */ + public static final int CAPABILITY_CHAT_SESSION = (1 << 1); + /** Supports full store and forward group chat information. */ + public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = (1 << 2); + /** + * Supports file transfer via Message Session Relay Protocol (MSRP) without Store and Forward. + */ + public static final int CAPABILITY_FILE_TRANSFER = (1 << 3); + /** Supports File Transfer Thumbnail */ + public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = (1 << 4); + /** Supports File Transfer with Store and Forward */ + public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = (1 << 5); + /** Supports File Transfer via HTTP */ + public static final int CAPABILITY_FILE_TRANSFER_HTTP = (1 << 6); + /** Supports file transfer via SMS */ + public static final int CAPABILITY_FILE_TRANSFER_SMS = (1 << 7); + /** Supports image sharing */ + public static final int CAPABILITY_IMAGE_SHARE = (1 << 8); + /** Supports video sharing during a circuit-switch call (IR.74)*/ + public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = (1 << 9); + /** Supports video share outside of voice call (IR.84) */ + public static final int CAPABILITY_VIDEO_SHARE = (1 << 10); + /** Supports social presence information */ + public static final int CAPABILITY_SOCIAL_PRESENCE = (1 << 11); + /** Supports capability discovery via presence */ + public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = (1 << 12); + /** Supports IP Voice calling over LTE or IWLAN (IR.92/IR.51) */ + public static final int CAPABILITY_IP_VOICE_CALL = (1 << 13); + /** Supports IP video calling (IR.94) */ + public static final int CAPABILITY_IP_VIDEO_CALL = (1 << 14); + /** Supports Geolocation PUSH during 1-to-1 or multiparty chat */ + public static final int CAPABILITY_GEOLOCATION_PUSH = (1 << 15); + /** Supports Geolocation PUSH via SMS for fallback. */ + public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = (1 << 16); + /** Supports Geolocation pull. */ + public static final int CAPABILITY_GEOLOCATION_PULL = (1 << 17); + /** Supports Geolocation pull using file transfer support. */ + public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = (1 << 18); + /** Supports RCS voice calling */ + public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19); + /** Supports RCS video calling */ + public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20); + /** Supports RCS video calling, where video media can not be dropped */ + public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21); + + /** @hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CAPABILITY_", flag = true, value = { + CAPABILITY_CHAT_STANDALONE, + CAPABILITY_CHAT_SESSION, + CAPABILITY_CHAT_SESSION_STORE_FORWARD, + CAPABILITY_FILE_TRANSFER, + CAPABILITY_FILE_TRANSFER_THUMBNAIL, + CAPABILITY_FILE_TRANSFER_STORE_FORWARD, + CAPABILITY_FILE_TRANSFER_HTTP, + CAPABILITY_FILE_TRANSFER_SMS, + CAPABILITY_IMAGE_SHARE, + CAPABILITY_VIDEO_SHARE_DURING_CS_CALL, + CAPABILITY_VIDEO_SHARE, + CAPABILITY_SOCIAL_PRESENCE, + CAPABILITY_DISCOVERY_VIA_PRESENCE, + CAPABILITY_IP_VOICE_CALL, + CAPABILITY_IP_VIDEO_CALL, + CAPABILITY_GEOLOCATION_PUSH, + CAPABILITY_GEOLOCATION_PUSH_SMS, + CAPABILITY_GEOLOCATION_PULL, + CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER, + CAPABILITY_RCS_VOICE_CALL, + CAPABILITY_RCS_VIDEO_CALL, + CAPABILITY_RCS_VIDEO_ONLY_CALL + }) + public @interface CapabilityFlag {} + + /** + * Builder to help construct {@link RcsContactUceCapability} instances. + */ + public static class Builder { + + private final RcsContactUceCapability mCapabilities; + + /** + * Create the Builder, which can be used to set UCE capabilities as well as custom + * capability extensions. + * @param contact The contact URI that the capabilities are attached to. + */ + public Builder(@NonNull Uri contact) { + mCapabilities = new RcsContactUceCapability(contact); + } + + /** + * Add a UCE capability bit-field as well as the associated URI that the framework should + * use for those services. This is mainly used for capabilities that may use a URI separate + * from the contact's URI, for example the URI to use for VT calls. + * @param type The capability to map to a service URI that is different from the contact's + * URI. + */ + public Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) { + mCapabilities.mCapabilities |= type; + // Put each of these capabilities into the map separately. + for (int shift = 0; shift < Integer.SIZE; shift++) { + int cap = type & (1 << shift); + if (cap != 0) { + mCapabilities.mServiceMap.put(cap, serviceUri); + // remove that capability from the field. + type &= ~cap; + } + if (type == 0) { + // no need to keep going, end early. + break; + } + } + return this; + } + + /** + * Add a UCE capability flag that this contact supports. + * @param type the capability that the contact supports. + */ + public Builder add(@CapabilityFlag int type) { + mCapabilities.mCapabilities |= type; + return this; + } + + /** + * Add a carrier specific service tag. + * @param extension A string containing a carrier specific service tag that is an extension + * of the {@link CapabilityFlag}s that are defined here. + */ + public Builder add(@NonNull String extension) { + mCapabilities.mExtensionTags.add(extension); + return this; + } + + /** + * @return the constructed instance. + */ + public RcsContactUceCapability build() { + return mCapabilities; + } + } + + private final Uri mContactUri; + private int mCapabilities; + private List<String> mExtensionTags = new ArrayList<>(); + private Map<Integer, Uri> mServiceMap = new HashMap<>(); + + /** + * Use {@link Builder} to build an instance of this interface. + * @param contact The URI associated with this capability information. + * @hide + */ + RcsContactUceCapability(@NonNull Uri contact) { + mContactUri = contact; + } + + private RcsContactUceCapability(Parcel in) { + mContactUri = in.readParcelable(Uri.class.getClassLoader()); + mCapabilities = in.readInt(); + in.readStringList(mExtensionTags); + // read mServiceMap as key,value pair + int mapSize = in.readInt(); + for (int i = 0; i < mapSize; i++) { + mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader())); + } + } + + public static final Creator<RcsContactUceCapability> CREATOR = + new Creator<RcsContactUceCapability>() { + @Override + public RcsContactUceCapability createFromParcel(Parcel in) { + return new RcsContactUceCapability(in); + } + + @Override + public RcsContactUceCapability[] newArray(int size) { + return new RcsContactUceCapability[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(mContactUri, 0); + out.writeInt(mCapabilities); + out.writeStringList(mExtensionTags); + // write mServiceMap as key,value pairs + int mapSize = mServiceMap.keySet().size(); + out.writeInt(mapSize); + for (int key : mServiceMap.keySet()) { + out.writeInt(key); + out.writeParcelable(mServiceMap.get(key), 0); + } + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Query for a capability + * @param type The capability flag to query. + * @return true if the capability flag specified is set, false otherwise. + */ + public boolean isCapable(@CapabilityFlag int type) { + return (mCapabilities & type) > 0; + } + + /** + * @return true if the extension service tag is set, false otherwise. + */ + public boolean isCapable(@NonNull String extensionTag) { + return mExtensionTags.contains(extensionTag); + } + + /** + * @return An immutable list containing all of the extension tags that have been set as capable. + * @throws UnsupportedOperationException if this list is modified. + */ + public @NonNull List<String> getCapableExtensionTags() { + return Collections.unmodifiableList(mExtensionTags); + } + + /** + * Retrieves the {@link Uri} associated with the capability being queried. + * <p> + * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless + * a different service {@link Uri} was associated with this capability using + * {@link Builder#add(int, Uri)}. + * + * @return a String containing the {@link Uri} associated with the service tag or + * {@code null} if this capability is not set as capable. + * @see #isCapable(int) + */ + public @Nullable Uri getServiceUri(@CapabilityFlag int type) { + Uri result = mServiceMap.getOrDefault(type, null); + // If the capability is capable, but does not have a service URI associated, use the default + // contact URI. + if (result == null) { + return isCapable(type) ? getContactUri() : null; + } + return result; + } + + /** + * @return the URI representing the contact associated with the capabilities. + */ + public @NonNull Uri getContactUri() { + return mContactUri; + } +} diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java new file mode 100644 index 000000000000..a6a7a84c2c65 --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -0,0 +1,276 @@ +/* + * 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; + +import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.net.Uri; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Manages RCS User Capability Exchange for the subscription specified. + * + * @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class. + * @hide + */ +public class RcsUceAdapter { + + /** + * An unknown error has caused the request to fail. + */ + public static final int ERROR_GENERIC_FAILURE = 1; + /** + * The carrier network does not have UCE support enabled for this subscriber. + */ + public static final int ERROR_NOT_ENABLED = 2; + /** + * The data network that the device is connected to does not support UCE currently (e.g. it is + * 1x only currently). + */ + public static final int ERROR_NOT_AVAILABLE = 3; + /** + * The network has responded with SIP 403 error and a reason "User not registered." + */ + public static final int ERROR_NOT_REGISTERED = 4; + /** + * The network has responded to this request with a SIP 403 error and reason "not authorized for + * presence" for this subscriber. + */ + public static final int ERROR_NOT_AUTHORIZED = 5; + /** + * The network has responded to this request with a SIP 403 error and no reason. + */ + public static final int ERROR_FORBIDDEN = 6; + /** + * The contact URI requested is not provisioned for VoLTE or it is not known as an IMS + * subscriber to the carrier network. + */ + public static final int ERROR_NOT_FOUND = 7; + /** + * The capabilities request contained too many URIs for the carrier network to handle. Retry + * with a lower number of contact numbers. The number varies per carrier. + */ + // TODO: Try to integrate this into the API so that the service will split based on carrier. + public static final int ERROR_REQUEST_TOO_LARGE = 8; + /** + * The network did not respond to the capabilities request before the request timed out. + */ + public static final int ERROR_REQUEST_TIMEOUT = 10; + /** + * The request failed due to the service having insufficient memory. + */ + public static final int ERROR_INSUFFICIENT_MEMORY = 11; + /** + * The network was lost while trying to complete the request. + */ + public static final int ERROR_LOST_NETWORK = 12; + /** + * The request has failed because the same request has already been added to the queue. + */ + public static final int ERROR_ALREADY_IN_QUEUE = 13; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "ERROR_", value = { + ERROR_GENERIC_FAILURE, + ERROR_NOT_ENABLED, + ERROR_NOT_AVAILABLE, + ERROR_NOT_REGISTERED, + ERROR_NOT_AUTHORIZED, + ERROR_FORBIDDEN, + ERROR_NOT_FOUND, + ERROR_REQUEST_TOO_LARGE, + ERROR_REQUEST_TIMEOUT, + ERROR_INSUFFICIENT_MEMORY, + ERROR_LOST_NETWORK, + ERROR_ALREADY_IN_QUEUE + }) + public @interface ErrorCode {} + + /** + * The last publish has resulted in a "200 OK" response or the device is using SIP OPTIONS for + * UCE. + */ + public static final int PUBLISH_STATE_200_OK = 1; + + /** + * The hasn't published its capabilities since boot or hasn't gotten any publish response yet. + */ + public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; + + /** + * The device has tried to publish its capabilities, which has resulted in an error. This error + * is related to the fact that the device is not VoLTE provisioned. + */ + public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; + + /** + * The device has tried to publish its capabilities, which has resulted in an error. This error + * is related to the fact that the device is not RCS or UCE provisioned. + */ + public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; + + /** + * The last publish resulted in a "408 Request Timeout" response. + */ + public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; + + /** + * The last publish resulted in another unknown error, such as SIP 503 - "Service Unavailable" + * or SIP 423 - "Interval too short". + * <p> + * Device shall retry with exponential back-off. + */ + public static final int PUBLISH_STATE_OTHER_ERROR = 6; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "PUBLISH_STATE_", value = { + PUBLISH_STATE_200_OK, + PUBLISH_STATE_NOT_PUBLISHED, + PUBLISH_STATE_VOLTE_PROVISION_ERROR, + PUBLISH_STATE_RCS_PROVISION_ERROR, + PUBLISH_STATE_REQUEST_TIMEOUT, + PUBLISH_STATE_OTHER_ERROR + }) + public @interface PublishState {} + + + /** + * Provides a one-time callback for the response to a UCE request. After this callback is called + * by the framework, the reference to this callback will be discarded on the service side. + * @see #requestCapabilities(Executor, List, CapabilitiesCallback) + */ + public static class CapabilitiesCallback { + + /** + * Notify this application that the pending capability request has returned successfully. + * @param contactCapabilities List of capabilities associated with each contact requested. + */ + public void onCapabilitiesReceived( + @NonNull List<RcsContactUceCapability> contactCapabilities) { + + } + + /** + * The pending request has resulted in an error and may need to be retried, depending on the + * error code. + * @param errorCode The reason for the framework being unable to process the request. + */ + public void onError(@ErrorCode int errorCode) { + + } + } + + private final int mSubId; + + /** + * Not to be instantiated directly, use + * {@link ImsRcsManager#createForSubscriptionId(Context, int)} and + * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class. + */ + RcsUceAdapter(int subId) { + mSubId = subId; + } + + /** + * Request the User Capability Exchange capabilities for one or more contacts. + * <p> + * Be sure to check the availability of this feature using + * {@link ImsRcsManager#isAvailable(int)} and ensuring + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else + * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}. + * + * @param executor The executor that will be used when the request is completed and the + * {@link CapabilitiesCallback} is called. + * @param contactNumbers A list of numbers that the capabilities are being requested for. + * @param c A one-time callback for when the request for capabilities completes or there is an + * error processing the request. + * @throws ImsException if the subscription associated with this instance of + * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not + * available. This can happen if the ImsService has crashed, for example, or if the subscription + * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void requestCapabilities(@CallbackExecutor Executor executor, + @NonNull List<Uri> contactNumbers, + @NonNull CapabilitiesCallback c) throws ImsException { + throw new UnsupportedOperationException("isUceSettingEnabled is not supported."); + } + + /** + * Gets the last publish result from the UCE service if the device is using an RCS presence + * server. + * @return The last publish result from the UCE service. If the device is using SIP OPTIONS, + * this method will return {@link #PUBLISH_STATE_200_OK} as well. + * @throws ImsException if the subscription associated with this instance of + * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not + * available. This can happen if the ImsService has crashed, for example, or if the subscription + * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public @PublishState int getUcePublishState() throws ImsException { + throw new UnsupportedOperationException("getPublishState is not supported."); + } + + /** + * The user’s setting for whether or not Presence and User Capability Exchange (UCE) is enabled + * for the associated subscription. + * + * @return true if the user’s setting for UCE is enabled, false otherwise. If false, + * {@link ImsRcsManager#isCapable(int)} will return false for + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} + * @see #setUceSettingEnabled(boolean) + * @throws ImsException if the subscription associated with this instance of + * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not + * available. This can happen if the ImsService has crashed, for example, or if the subscription + * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isUceSettingEnabled() throws ImsException { + // TODO: add SubscriptionController column for this property. + throw new UnsupportedOperationException("isUceSettingEnabled is not supported."); + } + /** + * Change the user’s setting for whether or not UCE is enabled for the associated subscription. + * @param isEnabled the user's setting for whether or not they wish for Presence and User + * Capability Exchange to be enabled. If false, + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and + * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} capability will be + * disabled, depending on which type of UCE the carrier supports. + * @see #isUceSettingEnabled() + * @throws ImsException if the subscription associated with this instance of + * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not + * available. This can happen if the ImsService has crashed, for example, or if the subscription + * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setUceSettingEnabled(boolean isEnabled) throws ImsException { + // TODO: add SubscriptionController column for this property. + throw new UnsupportedOperationException("setUceSettingEnabled is not supported."); + } +} diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index a637e16d0a48..5fae3eebbfc6 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -16,8 +16,14 @@ package android.telephony.ims.feature; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.telephony.ims.aidl.IImsRcsFeature; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; +import android.telephony.ims.stub.RcsSipOptionsImplBase; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend @@ -32,18 +38,165 @@ public class RcsFeature extends ImsFeature { // Empty Default Implementation. }; + /** + * Contains the capabilities defined and supported by a {@link RcsFeature} in the + * form of a bitmask. The capabilities that are used in the RcsFeature are + * defined as: + * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE} + * {@link RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE} + * + * The enabled capabilities of this RcsFeature will be set by the framework + * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}. + * After the capabilities have been set, the RcsFeature may then perform the necessary bring up + * of the capability and notify the capability status as true using + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the + * framework that the capability is available for usage. + * @hide + */ + public static class RcsImsCapabilities extends Capabilities { + /** @hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = { + CAPABILITY_TYPE_OPTIONS_UCE, + CAPABILITY_TYPE_PRESENCE_UCE + }) + public @interface RcsImsCapabilityFlag {} - public RcsFeature() { - super(); + /** + * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the + * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS. + * If not set, this RcsFeature should not service capability requests. + * @hide + */ + public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0; + + /** + * This carrier supports User Capability Exchange using a presence server as defined by the + * framework. If set, the RcsFeature should support capability exchange using a presence + * server. If not set, this RcsFeature should not publish capabilities or service capability + * requests using presence. + * @hide + */ + public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1; + + /**@hide*/ + public RcsImsCapabilities(@RcsImsCapabilityFlag int capabilities) { + + } + + /**@hide*/ + @Override + public void addCapabilities(@RcsImsCapabilityFlag int capabilities) { + + } + + /**@hide*/ + @Override + public void removeCapabilities(@RcsImsCapabilityFlag int capabilities) { + + } + + /**@hide*/ + @Override + public boolean isCapable(@RcsImsCapabilityFlag int capabilities) { + return false; + } + } + /** + * 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 + * requests. To change the status of the capabilities + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called. + * @hide + */ + @Override + public final RcsImsCapabilities queryCapabilityStatus() { + throw new UnsupportedOperationException(); } /** - * {@inheritDoc} + * Notify the framework that the capabilities status has changed. If a capability is enabled, + * this signals to the framework that the capability has been initialized and is ready. + * Call {@link #queryCapabilityStatus()} to return the current capability status. + * @hide + */ + public final void notifyCapabilitiesStatusChanged(RcsImsCapabilities c) { + throw new UnsupportedOperationException(); + } + + /** + * Provides the RcsFeature with the ability to return the framework capability configuration set + * by the framework. When the framework calls + * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to + * enable or disable capability A, this method should return the correct configuration for + * capability A afterwards (until it has changed). + * @hide + */ + public boolean queryCapabilityConfiguration( + @RcsImsCapabilities.RcsImsCapabilityFlag int capability) { + throw new UnsupportedOperationException(); + } + /** + * Called from the framework when the {@link RcsImsCapabilities} that have been configured for + * this {@link RcsFeature} has changed. + * <p> + * For each newly enabled capability flag, the corresponding capability should be brought up in + * the {@link RcsFeature} and registered on the network. For each newly disabled capability + * flag, the corresponding capability should be brought down, and deregistered. Once a new + * capability has been initialized and is ready for usage, the status of that capability should + * also be set to true using {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This + * will notify the framework that the capability is ready. + * <p> + * If for some reason one or more of these capabilities can not be enabled/disabled, + * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should + * be called for each capability change that resulted in an error. + * @hide */ @Override public void changeEnabledCapabilities(CapabilityChangeRequest request, CapabilityCallbackProxy c) { - // Do nothing for base implementation. + throw new UnsupportedOperationException(); + } + + /** + * Retrieve the implementation of SIP OPTIONS for this {@link RcsFeature}. + * <p> + * Will only be requested by the framework if capability exchange via SIP OPTIONS is + * configured as capable during a + * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} + * operation and the RcsFeature sets the status of the capability to true using + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. + * + * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if + * it is supported by the device. + * @hide + */ + public RcsSipOptionsImplBase getOptionsExchangeImpl() { + // Base Implementation, override to implement functionality + return new RcsSipOptionsImplBase(); + } + + /** + * Retrieve the implementation of UCE presence for this {@link RcsFeature}. + * Will only be requested by the framework if presence exchang is configured as capable during + * a {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} + * operation and the RcsFeature sets the status of the capability to true using + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. + * + * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence + * exchange if it is supported by the device. + * @hide + */ + public RcsPresenceExchangeImplBase getPresenceExchangeImpl() { + // Base Implementation, override to implement functionality. + return new RcsPresenceExchangeImplBase(); + } + + /** + * Construct a new {@link RcsFeature} instance. + */ + public RcsFeature() { + super(); } /**{@inheritDoc}*/ diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 321bfff40652..4bd49e006da8 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -342,6 +342,17 @@ public class ImsConfigImplBase { } /** + * The framework has received an RCS autoconfiguration XML file for provisioning. + * + * @param config The XML file to be read, if not compressed, it should be in ASCII/UTF8 format. + * @param isCompressed The XML file is compressed in gzip format and must be decompressed + * before being read. + * @hide + */ + public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) { + } + + /** * Sets the configuration value for this ImsService. * * @param item an integer key. diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java new file mode 100644 index 000000000000..289fd4c8a134 --- /dev/null +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java @@ -0,0 +1,89 @@ +/* + * 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.stub; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base class for different types of Capability exchange, presence using + * {@link RcsPresenceExchangeImplBase} and SIP OPTIONS exchange using {@link RcsSipOptionsImplBase}. + * + * @hide + */ +public class RcsCapabilityExchange { + + /** Service is unknown. */ + public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; + /** The command completed successfully. */ + public static final int COMMAND_CODE_SUCCESS = 1; + /** The command failed with an unknown error. */ + public static final int COMMAND_CODE_GENERIC_FAILURE = 2; + /** Invalid parameter(s). */ + public static final int COMMAND_CODE_INVALID_PARAM = 3; + /** Fetch error. */ + public static final int COMMAND_CODE_FETCH_ERROR = 4; + /** Request timed out. */ + public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; + /** Failure due to insufficient memory available. */ + public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; + /** Network connection is lost. */ + public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; + /** Requested feature/resource is not supported. */ + public static final int COMMAND_CODE_NOT_SUPPORTED = 8; + /** Contact or resource is not found. */ + public static final int COMMAND_CODE_NOT_FOUND = 9; + /** Service is not available. */ + public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; + /** No Change in Capabilities */ + public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; + + /** @hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "COMMAND_CODE_", value = { + COMMAND_CODE_SERVICE_UNKNOWN, + COMMAND_CODE_SUCCESS, + COMMAND_CODE_GENERIC_FAILURE, + COMMAND_CODE_INVALID_PARAM, + COMMAND_CODE_FETCH_ERROR, + COMMAND_CODE_REQUEST_TIMEOUT, + COMMAND_CODE_INSUFFICIENT_MEMORY, + COMMAND_CODE_LOST_NETWORK_CONNECTION, + COMMAND_CODE_NOT_SUPPORTED, + COMMAND_CODE_NOT_FOUND, + COMMAND_CODE_SERVICE_UNAVAILABLE, + COMMAND_CODE_NO_CHANGE_IN_CAP + }) + public @interface CommandCode {} + + /** + * 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 + * complete successfully, then the framework may retry the command again later, depending on the + * error. If the command does complete successfully, the framework will then wait for network + * updates. + * + * @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. + */ + public final void onCommandUpdate(@CommandCode int code, int operationToken) { + throw new UnsupportedOperationException(); + } +} diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java new file mode 100644 index 000000000000..44024703042d --- /dev/null +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -0,0 +1,191 @@ +/* + * 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.stub; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.net.Uri; +import android.telephony.ims.RcsContactUceCapability; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +/** + * Base implementation for RCS User Capability Exchange using Presence. Any ImsService implementing + * this service must implement the stub methods {@link #requestCapabilities(List, int)} and + * {@link #updateCapabilities(RcsContactUceCapability, int)}. + * + * @hide + */ +public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { + + private static final String LOG_TAG = "RcsPresenceExchangeIB"; + + /** + * The request has resulted in any other 4xx/5xx/6xx that is not covered below. No retry will be + * attempted. + */ + public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; + + /** + * The request has succeeded with a “200” message from the network. + */ + public static final int RESPONSE_SUCCESS = 0; + + /** + * The request has resulted in a “403” (User Not Registered) error from the network. Will retry + * capability polling with an exponential backoff. + */ + public static final int RESPONSE_NOT_REGISTERED = 1; + + /** + * The request has resulted in a “403” (not authorized (Requestor)) error from the network. No + * retry will be attempted. + */ + public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; + + /** + * The request has resulted in a "403” (Forbidden) or other “403” error from the network and + * will be handled the same as “404” Not found. No retry will be attempted. + */ + public static final int RESPONSE_FORBIDDEN = 3; + + /** + * The request has resulted in a “404” (Not found) result from the network. No retry will be + * attempted. + */ + public static final int RESPONSE_NOT_FOUND = 4; + + /** + * The request has resulted in a “408” response. Retry after exponential backoff. + */ + public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; + + /** + * The network has responded with a “413” (Too Large) response from the network. Capability + * request contains too many items and must be shrunk before the request will be accepted. + */ + public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; + + /** + * The request has resulted in a “423” response. Retry after exponential backoff. + */ + public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; + + /** + * The request has resulted in a “503” response. Retry after exponential backoff. + */ + public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; + + /** @hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "RESPONSE_", value = { + RESPONSE_SUBSCRIBE_GENERIC_FAILURE, + RESPONSE_SUCCESS, + RESPONSE_NOT_REGISTERED, + RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE, + RESPONSE_FORBIDDEN, + RESPONSE_NOT_FOUND, + RESPONSE_SIP_REQUEST_TIMEOUT, + RESPONSE_SUBSCRIBE_TOO_LARGE, + RESPONSE_SIP_INTERVAL_TOO_SHORT, + RESPONSE_SIP_SERVICE_UNAVAILABLE + }) + public @interface PresenceResponseCode {} + + /** + * 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. + */ + public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason, + int operationToken) { + throw new UnsupportedOperationException(); + } + + /** + * Provides the framework with the requested contacts’ capabilities requested by the framework + * using {@link #requestCapabilities(List, int)} . + */ + public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos, + int operationToken) { + throw new UnsupportedOperationException(); + } + + /** + * 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. + * <p> + * The device will cache all presence publications after boot until this method is called once. + */ + public final void onNotifyUpdateCapabilites() { + throw new UnsupportedOperationException(); + } + + /** + * Notify the framework that the device’s capabilities have been unpublished from the network. + */ + public final void onUnpublish() { + throw new UnsupportedOperationException(); + } + + /** + * The user capabilities of one or multiple contacts have been requested. + * <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. + * @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 + * in response. + */ + 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); + } + + /** + * 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)}. + * @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)} + * calls regarding this update must use the same token. + */ + public void updateCapabilities(@NonNull RcsContactUceCapability capabilities, + int operationToken) { + // Stub - to be implemented by service + Log.w(LOG_TAG, "updateCapabilities called with no implementation."); + onCommandUpdate(COMMAND_CODE_GENERIC_FAILURE, operationToken); + } +} diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java new file mode 100644 index 000000000000..3343074ea52c --- /dev/null +++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java @@ -0,0 +1,169 @@ +/* + * 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.stub; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Uri; +import android.telephony.ims.RcsContactUceCapability; +import android.util.Log; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base implementation for RCS User Capability Exchange using SIP OPTIONS. + * + * @hide + */ +public class RcsSipOptionsImplBase extends RcsCapabilityExchange { + + private static final String LOG_TAG = "RcsSipOptionsImplBase"; + + /** + * Indicates a SIP response from the remote user other than 200, 480, 408, 404, or 604. + */ + public static final int RESPONSE_GENERIC_FAILURE = -1; + + /** + * Indicates that the remote user responded with a 200 OK response. + */ + public static final int RESPONSE_SUCCESS = 0; + + /** + * Indicates that the remote user responded with a 480 TEMPORARY UNAVAILABLE response. + */ + public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; + + /** + * Indicates that the remote user responded with a 408 REQUEST TIMEOUT response. + */ + public static final int RESPONSE_REQUEST_TIMEOUT = 2; + + /** + * Indicates that the remote user responded with a 404 NOT FOUND response. + */ + public static final int RESPONSE_NOT_FOUND = 3; + + /** + * Indicates that the remote user responded with a 604 DOES NOT EXIST ANYWHERE response. + */ + public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; + + /** @hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "RESPONSE_", value = { + RESPONSE_GENERIC_FAILURE, + RESPONSE_SUCCESS, + RESPONSE_TEMPORARILY_UNAVAILABLE, + RESPONSE_REQUEST_TIMEOUT, + RESPONSE_NOT_FOUND, + RESPONSE_DOES_NOT_EXIST_ANYWHERE + }) + public @interface SipResponseCode {} + + /** + * Send the response of a SIP OPTIONS capability exchange to the framework. If {@code code} is + * {@link #RESPONSE_SUCCESS}, info must be non-null. + * @param code The SIP response code that was sent by the network in response to the request + * sent by {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}. + * @param reason The optional SIP response reason sent by the network. If none was sent, this + * should be an empty string. + * @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)}. + */ + public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason, + @Nullable RcsContactUceCapability info, int operationToken) { + throw new UnsupportedOperationException(); + } + + /** + * Inform the framework of a query for this device's UCE capabilities. + * <p> + * The framework will respond via the + * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)} or + * {@link #respondToCapabilityRequestWithError(Uri, int, String, int)} method. + * @param contactUri The URI associated with the remote contact that is requesting capabilities. + * @param remoteInfo The remote contact's capability information. + * @param operationToken An unique operation token that you have generated that will be returned + * by the framework in + * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}. + */ + public final void onRemoteCapabilityRequest(@NonNull Uri contactUri, + @NonNull RcsContactUceCapability remoteInfo, int operationToken) { + throw new UnsupportedOperationException(); + } + + /** + * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism + * in order to receive the capabilities of the remote user in response. + * <p> + * The implementer must call + * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} to send the + * response of this query back to the framework. + * @param contactUri The URI of the remote user that we wish to get the capabilities of. + * @param capabilities The capabilities of this device to send to the remote user. + * @param operationToken A token generated by the framework that will be passed through + * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} when this + * operation has succeeded. + */ + public void sendCapabilityRequest(@NonNull Uri contactUri, + @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); + } + + /** + * Respond to a remote capability request from the contact specified with the capabilities of + * this device. + * <p> + * The framework will use the same token and uri as what was passed in to + * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}. + * @param contactUri The URI of the remote contact. + * @param ownCapabilities The capabilities of this device. + * @param operationToken The token generated by the framework that this service obtained when + * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called. + */ + public void respondToCapabilityRequest(@NonNull String contactUri, + @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); + } + + /** + * Respond to a remote capability request from the contact specified with the specified error. + * <p> + * The framework will use the same token and uri as what was passed in to + * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}. + * @param contactUri A URI containing the remote contact. + * @param code The SIP response code to respond with. + * @param reason A non-null String containing the reason associated with the SIP code. + * @param operationToken The token provided by the framework when + * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called. + * + */ + public void respondToCapabilityRequestWithError(@NonNull Uri contactUri, + @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); + } +} |