Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d36c75a authored by Brad Ebinger's avatar Brad Ebinger Committed by android-build-merger
Browse files

Merge "Add APIs for ImsService RCS UCE implementation"

am: 01f09350

Change-Id: Ic4953e05afa2187e4566aaba5799dc800e61f548
parents a1e96c64 01f09350
Loading
Loading
Loading
Loading
+234 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+18 −0
Original line number Diff line number Diff line
@@ -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) {
+20 −0
Original line number Diff line number Diff line
/*
 * 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;
+291 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+276 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading