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

Commit 01f09350 authored by Brad Ebinger's avatar Brad Ebinger Committed by Gerrit Code Review
Browse files

Merge "Add APIs for ImsService RCS UCE implementation"

parents f0723588 c2a60b20
Loading
Loading
Loading
Loading
+234 −0
Original line number Original line 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 Original line 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() {
    private static boolean isImsAvailableOnDevice() {
        IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
        IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
        if (pm == null) {
        if (pm == null) {
+20 −0
Original line number Original line 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 Original line 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