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

Commit 79e74c78 authored by Brad Ebinger's avatar Brad Ebinger Committed by android-build-merger
Browse files

Integrate Registration APIs

am: 0e170c7f

Change-Id: If262feac39f40a3c59a4b0ad1e810c72568df231
parents e0e696b0 0e170c7f
Loading
Loading
Loading
Loading
+33 −2
Original line number Diff line number Diff line
@@ -17,15 +17,42 @@
package com.android.ims;

import android.net.Uri;
import android.telephony.ims.stub.ImsRegistrationImplBase;

/**
 * Listener for receiving notifications about changes to the IMS connection.
 * It provides a state of IMS registration between UE and IMS network, the service
 * availability of the local device during IMS registered.
 *
 * @Deprecated Use {@link ImsRegistrationImplBase.Callback} instead.
 * @hide
 */
public class ImsConnectionStateListener {
public class ImsConnectionStateListener extends ImsRegistrationImplBase.Callback {

    @Override
    public final void onRegistered(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
        onImsConnected(imsRadioTech);
    }

    @Override
    public final void onRegistering(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
        onImsProgressing(imsRadioTech);
    }

    @Override
    public final void onDeregistered(ImsReasonInfo info) {
        onImsDisconnected(info);
    }

    @Override
    public final void onTechnologyChangeFailed(
            @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) {
        onRegistrationChangeFailed(imsRadioTech, info);
    }

    @Override
    public void onSubscriberAssociatedUriChanged(Uri[] uris) {
        registrationAssociatedUriChanged(uris);
    }
    /**
     * Called when the device is connected to the IMS network with {@param imsRadioTech}.
     */
@@ -50,6 +77,7 @@ public class ImsConnectionStateListener {
    /**
     * Called when its suspended IMS connection is resumed, meaning the connection
     * now allows throughput.
     * @deprecated not used in newer IMS provider implementations.
     */
    public void onImsResumed() {
        // no-op
@@ -57,6 +85,7 @@ public class ImsConnectionStateListener {

    /**
     * Called when its current IMS connection is suspended, meaning there is no data throughput.
     * @deprecated not used in newer IMS provider implementations.
     */
    public void onImsSuspended() {
        // no-op
@@ -64,6 +93,7 @@ public class ImsConnectionStateListener {

    /**
     * Called when its current IMS connection feature capability changes.
     * @deprecated Not used in newer IMS provider implementations.
     */
    public void onFeatureCapabilityChanged(int serviceClass,
                int[] enabledFeatures, int[] disabledFeatures) {
@@ -72,6 +102,7 @@ public class ImsConnectionStateListener {

    /**
     * Called when waiting voice message count changes.
     * @deprecated not used in newer IMS provider implementations.
     */
    public void onVoiceMessageCountChanged(int count) {
        // no-op
+91 −56
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.os.Message;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
import android.telecom.TelecomManager;
@@ -37,16 +36,14 @@ import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.feature.ImsFeature;
import android.util.Log;

import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMMTelFeature;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationCallback;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsServiceController;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.ImsCallSession;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,6 +56,7 @@ import java.util.HashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
@@ -82,13 +80,6 @@ public class ImsManager {
    public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off";
    public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0;

    /**
     * For accessing the IMS related service.
     * Internal use only.
     * @hide
     */
    private static final String IMS_SERVICE = "ims";

    /**
     * The result code to be sent back with the incoming call {@link PendingIntent}.
     * @see #open(PendingIntent, ImsConnectionStateListener)
@@ -197,14 +188,20 @@ public class ImsManager {

    private ImsMultiEndpoint mMultiEndpoint = null;

    private Set<ImsServiceProxy.INotifyStatusChanged> mStatusCallbacks = new HashSet<>();
    private Set<ImsServiceProxy.IFeatureUpdate> mStatusCallbacks = new CopyOnWriteArraySet<>();

    // Keep track of the ImsRegistrationListenerProxys that have been created so that we can
    // remove them from the ImsService.
    private final Set<ImsConnectionStateListener> mRegistrationListeners = new HashSet<>();

    private final ImsRegistrationListenerProxy mRegistrationListenerProxy =

    // Used for compatibility with the old Registration method
    // TODO: Remove once the compat layer is in place
    private final ImsRegistrationListenerProxy mImsRegistrationListenerProxy =
            new ImsRegistrationListenerProxy();
    // New API for registration to the ImsService.
    private final ImsRegistrationCallback mRegistrationCallback = new ImsRegistrationCallback();


    // When true, we have registered the mRegistrationListenerProxy with the ImsService. Don't do
    // it again.
@@ -1409,7 +1406,7 @@ public class ImsManager {
     * Adds a callback for status changed events if the binder is already available. If it is not,
     * this method will throw an ImsException.
     */
    public void addNotifyStatusChangedCallbackIfAvailable(ImsServiceProxy.INotifyStatusChanged c)
    public void addNotifyStatusChangedCallbackIfAvailable(ImsServiceProxy.IFeatureUpdate c)
            throws ImsException {
        if (!mImsServiceProxy.isBinderAlive()) {
            throw new ImsException("Binder is not active!",
@@ -1420,6 +1417,14 @@ public class ImsManager {
        }
    }

    public void removeNotifyStatusChangedCallback(ImsServiceProxy.IFeatureUpdate c) {
        if (c != null) {
            mStatusCallbacks.remove(c);
        } else {
            Log.w(TAG, "removeNotifyStatusChangedCallback: callback is null!");
        }
    }

    /**
     * Opens the IMS service for making calls and/or receiving generic IMS calls.
     * The caller may make subsquent calls through {@link #makeCall}.
@@ -1504,9 +1509,7 @@ public class ImsManager {
     * @throws NullPointerException if {@code listener} is null
     * @throws ImsException if calling the IMS service results in an error
     */
    public void addRegistrationListener(ImsConnectionStateListener listener)
            throws ImsException {

    public void addRegistrationListener(ImsConnectionStateListener listener) throws ImsException {
        if (listener == null) {
            throw new NullPointerException("listener can't be null");
        }
@@ -1515,8 +1518,11 @@ public class ImsManager {
            if (!mHasRegisteredForProxy) {
                try {
                    checkAndThrowExceptionIfServiceUnavailable();
                    mImsServiceProxy.addRegistrationListener(mRegistrationListenerProxy);
                    log("RegistrationListenerProxy registered.");
                    // TODO: Remove once new MmTelFeature is merged in
                    mImsServiceProxy.addRegistrationListener(mImsRegistrationListenerProxy);
                    mImsServiceProxy.getRegistration().addRegistrationCallback(
                            mRegistrationCallback);
                    log("Registration Callback/Listener registered.");
                    // Only record if there isn't a RemoteException.
                    mHasRegisteredForProxy = true;
                } catch (RemoteException e) {
@@ -1956,51 +1962,29 @@ public class ImsManager {
     */
    private void createImsService() {
        if (!mConfigDynamicBind) {
            // Old method of binding
            // Deprecated method of binding
            Rlog.i(TAG, "Creating ImsService using ServiceManager");
            mImsServiceProxy = getServiceProxyCompat();
            mImsServiceProxy = ImsServiceProxyCompat.create(mPhoneId, mDeathRecipient);
        } else {
            Rlog.i(TAG, "Creating ImsService using ImsResolver");
            mImsServiceProxy = getServiceProxy();
        }
        // We have created a new ImsService connection, signal for re-registration
        synchronized (mHasRegisteredLock) {
            mHasRegisteredForProxy = false;
        }
    }

    // Deprecated method of binding with the ImsService defined in the ServiceManager.
    private ImsServiceProxyCompat getServiceProxyCompat() {
        IBinder binder = ServiceManager.checkService(IMS_SERVICE);

        if (binder != null) {
            try {
                binder.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
            mImsServiceProxy = ImsServiceProxy.create(mContext, mPhoneId);
        }
        // Forwarding interface to tell mStatusCallbacks that the Proxy is unavailable.
        mImsServiceProxy.setStatusCallback(new ImsServiceProxy.IFeatureUpdate() {
            @Override
            public void notifyStateChanged() {
                mStatusCallbacks.forEach(ImsServiceProxy.IFeatureUpdate::notifyStateChanged);
            }

        return new ImsServiceProxyCompat(mPhoneId, binder);
            @Override
            public void notifyUnavailable() {
                mStatusCallbacks.forEach(ImsServiceProxy.IFeatureUpdate::notifyUnavailable);
            }

    // New method of binding with the ImsResolver
    private ImsServiceProxy getServiceProxy() {
        TelephonyManager tm = (TelephonyManager)
                mContext.getSystemService(Context.TELEPHONY_SERVICE);
        ImsServiceProxy serviceProxy = new ImsServiceProxy(mPhoneId, ImsFeature.MMTEL);
        serviceProxy.setStatusCallback(() ->  mStatusCallbacks.forEach(
                ImsServiceProxy.INotifyStatusChanged::notifyStatusChanged));
        // Returns null if the service is not available.
        IImsMMTelFeature b = tm.getImsMMTelFeatureAndListen(mPhoneId,
                serviceProxy.getListener());
        if (b != null) {
            serviceProxy.setBinder(b.asBinder());
            // Trigger the cache to be updated for feature status.
            serviceProxy.getFeatureStatus();
        } else {
            Rlog.w(TAG, "getServiceProxy: b is null! Phone Id: " + mPhoneId);
        });
        // We have created a new ImsService connection, signal for re-registration
        synchronized (mHasRegisteredLock) {
            mHasRegisteredForProxy = false;
        }
        return serviceProxy;
    }

    /**
@@ -2333,6 +2317,57 @@ public class ImsManager {
        }
    }

    // New API for Registration, uses ImsConnectionStateListener for backwards compatibility with
    // deprecated APIs.
    private class ImsRegistrationCallback extends IImsRegistrationCallback.Stub {

        @Override
        public void onRegistered(int imsRadioTech) {
            if (DBG) log("onRegistered ::");

            synchronized (mRegistrationListeners) {
                mRegistrationListeners.forEach(l -> l.onRegistered(imsRadioTech));
            }
        }

        @Override
        public void onRegistering(int imsRadioTech) {
            if (DBG) log("onRegistering ::");

            synchronized (mRegistrationListeners) {
                mRegistrationListeners.forEach(l -> l.onRegistering(imsRadioTech));
            }
        }

        @Override
        public void onDeregistered(ImsReasonInfo imsReasonInfo) {
            if (DBG) log("onDeregistered ::");

            synchronized (mRegistrationListeners) {
                mRegistrationListeners.forEach(l -> l.onDeregistered(imsReasonInfo));
            }
        }

        @Override
        public void onTechnologyChangeFailed(int targetRadioTech, ImsReasonInfo imsReasonInfo) {
            if (DBG) log("onTechnologyChangeFailed :: targetAccessTech=" + targetRadioTech +
                    ", imsReasonInfo=" + imsReasonInfo);

            synchronized (mRegistrationListeners) {
                mRegistrationListeners.forEach(l -> l.onTechnologyChangeFailed(targetRadioTech,
                        imsReasonInfo));
            }
        }

        @Override
        public void onSubscriberAssociatedUriChanged(Uri[] uris) {
            if (DBG) log("onSubscriberAssociatedUriChanged");
            synchronized (mRegistrationListeners) {
                mRegistrationListeners.forEach(l -> l.onSubscriberAssociatedUriChanged(uris));
            }
        }
    }

    /**
     * Gets the ECBM interface to request ECBM exit.
     *
+64 −12
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package com.android.ims;

import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Context;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.telephony.ims.feature.ImsFeature;
import android.util.Log;

@@ -29,6 +33,7 @@ import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMMTelFeature;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistration;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.ims.internal.IImsUt;
@@ -41,20 +46,58 @@ import com.android.ims.internal.IImsUt;

public class ImsServiceProxy {

    protected String LOG_TAG = "ImsServiceProxy";
    protected static final String TAG = "ImsServiceProxy";
    protected final int mSlotId;
    protected IBinder mBinder;
    private final int mSupportedFeature;
    private Context mContext;

    // Start by assuming the proxy is available for usage.
    private boolean mIsAvailable = true;
    // ImsFeature Status from the ImsService. Cached.
    private Integer mFeatureStatusCached = null;
    private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
    private IFeatureUpdate mStatusCallback;
    private final Object mLock = new Object();

    public interface INotifyStatusChanged {
        void notifyStatusChanged();
    public static ImsServiceProxy create(Context context , int slotId) {
        ImsServiceProxy serviceProxy = new ImsServiceProxy(context, slotId, ImsFeature.MMTEL);

        TelephonyManager tm  = getTelephonyManager(context);
        if (tm == null) {
            Rlog.w(TAG, "getServiceProxy: TelephonyManager is null!");
            // Binder can be unset in this case because it will be torn down/recreated as part of
            // a retry mechanism until the serviceProxy binder is set successfully.
            return serviceProxy;
        }

        IImsMMTelFeature binder = tm.getImsMMTelFeatureAndListen(slotId,
                serviceProxy.getListener());
        if (binder != null) {
            serviceProxy.setBinder(binder.asBinder());
            // Trigger the cache to be updated for feature status.
            serviceProxy.getFeatureStatus();
        } else {
            Rlog.w(TAG, "getServiceProxy: binder is null! Phone Id: " + slotId);
        }
        return serviceProxy;
    }

    public static TelephonyManager getTelephonyManager(Context context) {
        return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    }

    public interface IFeatureUpdate {
        /**
         * Called when the ImsFeature has changed its state. Use
         * {@link ImsFeature#getFeatureState()} to get the new state.
         */
        void notifyStateChanged();

        /**
         * Called when the ImsFeature has become unavailable due to the binder switching or app
         * crashing. A new ImsServiceProxy should be requested for that feature.
         */
        void notifyUnavailable();
    }

    private final IImsServiceFeatureCallback mListenerBinder =
@@ -65,7 +108,7 @@ public class ImsServiceProxy {
            // The feature has been re-enabled. This may happen when the service crashes.
            synchronized (mLock) {
                if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
                    Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
                    Log.i(TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
                            feature);
                    mIsAvailable = true;
                }
@@ -76,9 +119,12 @@ public class ImsServiceProxy {
        public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
            synchronized (mLock) {
                if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
                    Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
                    Log.i(TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
                            feature);
                    mIsAvailable = false;
                    if (mStatusCallback != null) {
                        mStatusCallback.notifyUnavailable();
                    }
                }
            }
        }
@@ -86,12 +132,12 @@ public class ImsServiceProxy {
        @Override
        public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
            synchronized (mLock) {
                Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
                Log.i(TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
                        " status: " + status);
                if (mSlotId == slotId && feature == mSupportedFeature) {
                    mFeatureStatusCached = status;
                    if (mStatusCallback != null) {
                        mStatusCallback.notifyStatusChanged();
                        mStatusCallback.notifyStateChanged();
                    }
                }
            }
@@ -104,8 +150,14 @@ public class ImsServiceProxy {
        mSupportedFeature = featureType;
    }

    public ImsServiceProxy(int slotId, int featureType) {
    public ImsServiceProxy(Context context, int slotId, int featureType) {
        this(slotId, null, featureType);
        mContext = context;
    }

    public @Nullable IImsRegistration getRegistration() {
        TelephonyManager tm = getTelephonyManager(mContext);
        return tm != null ? tm.getImsRegistration(mSlotId, ImsFeature.MMTEL) : null;
    }

    public IImsServiceFeatureCallback getListener() {
@@ -246,7 +298,7 @@ public class ImsServiceProxy {
    public int getFeatureStatus() {
        synchronized (mLock) {
            if (isBinderAlive() && mFeatureStatusCached != null) {
                Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
                Log.i(TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
                return mFeatureStatusCached;
            }
        }
@@ -259,7 +311,7 @@ public class ImsServiceProxy {
            // Cache only non-null value for feature status.
            mFeatureStatusCached = status;
        }
        Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
        Log.i(TAG, "getFeatureStatus - returning " + status);
        return status;
    }

@@ -280,7 +332,7 @@ public class ImsServiceProxy {
    /**
     * @param c Callback that will fire when the feature status has changed.
     */
    public void setStatusCallback(INotifyStatusChanged c) {
    public void setStatusCallback(IFeatureUpdate c) {
        mStatusCallback = c;
    }

+27 −0
Original line number Diff line number Diff line
@@ -17,15 +17,20 @@
package com.android.ims;

import android.app.PendingIntent;
import android.content.Context;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.telephony.ims.feature.ImsFeature;

import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
import com.android.ims.internal.IImsConfig;
import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsMMTelFeature;
import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsService;
@@ -42,6 +47,28 @@ public class ImsServiceProxyCompat extends ImsServiceProxy {

    private static final int SERVICE_ID = ImsFeature.MMTEL;

    /**
     * For accessing the IMS related service.
     * Internal use only.
     * @hide
     */
    private static final String IMS_SERVICE = "ims";

    public static ImsServiceProxyCompat create(int slotId, IBinder.DeathRecipient recipient) {
        IBinder binder = ServiceManager.checkService(IMS_SERVICE);

        if (binder != null) {
            try {
                binder.linkToDeath(recipient, 0);
            } catch (RemoteException e) {
            }
        }

        // If the proxy is created with a null binder, subsequent calls that depend on a live
        // binder will fail, causing this structure to be torn down and created again.
        return new ImsServiceProxyCompat(slotId, binder);
    }

    public ImsServiceProxyCompat(int slotId, IBinder binder) {
        super(slotId, binder, SERVICE_ID);
    }