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

Commit 5f6a5219 authored by Brad Ebinger's avatar Brad Ebinger
Browse files

Framework Integration of dynamic query for ImsService

1) Adds support for dynamic query of ImsService features.
When the ImsResolver is notified of a change to the ImsService
package (via PackageManager or CarrierConfig), we perform
an async query to the affected ImsService. The updated
feature configuration is then saved to the ImsServiceInfo
cache and features are recalculated. This will cause the
Service to create/remove features according to this
config. We currently keep the ability for "compat"
ImsServices and device default ImsServices to communicate
their feature configurations via manifest query, but
all carrier ImsServices will need to do a dynamic query
to relay feature configuration information.

2) Fixes issue where we were sometimes not unbinding
to ImsServices, even if there were no features assigned.

3) We now drop down to the device default ImsService
when the SIM card is removed.

Test: Telephony Unit Tests, Telephony Test ImsService
Bug: 72642524

Merged-In: If65f25eb6b0696b38bd55b96c1d5a64d2a112a6b
Change-Id: Ieafa99c1454606016c71e4d183adf445f4189dc2
parent e4fbf65d
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -155,7 +155,7 @@ public class PhoneFactory {
                Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);
                Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);
                sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones,
                sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones,
                        isDynamicBinding);
                        isDynamicBinding);
                sImsResolver.populateCacheAndStartBind();
                sImsResolver.initPopulateCacheAndStartBind();


                int[] networkModes = new int[numPhones];
                int[] networkModes = new int[numPhones];
                sPhones = new Phone[numPhones];
                sPhones = new Phone[numPhones];
+431 −134

File changed.

Preview size limit exceeded, changes collapsed.

+87 −44
Original line number Original line Diff line number Diff line
@@ -34,8 +34,8 @@ import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.util.Log;
import android.util.Log;
import android.util.Pair;


import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -50,16 +50,15 @@ import java.util.Set;
 * Manages the Binding lifecycle of one ImsService as well as the relevant ImsFeatures that the
 * Manages the Binding lifecycle of one ImsService as well as the relevant ImsFeatures that the
 * ImsService will support.
 * ImsService will support.
 *
 *
 * When the ImsService is first bound, {@link IImsServiceController#createImsFeature} will be
 * When the ImsService is first bound, {@link ImsService#createMmTelFeature(int)} and
 * called
 * {@link ImsService#createRcsFeature(int)} will be called
 * on each feature that the service supports. For each ImsFeature that is created,
 * on each feature that the service supports. For each ImsFeature that is created,
 * {@link ImsServiceControllerCallbacks#imsServiceFeatureCreated} will be called to notify the
 * {@link ImsServiceControllerCallbacks#imsServiceFeatureCreated} will be called to notify the
 * listener that the ImsService now supports that feature.
 * listener that the ImsService now supports that feature.
 *
 *
 * When {@link #changeImsServiceFeatures} is called with a set of features that is different from
 * When {@link #changeImsServiceFeatures} is called with a set of features that is different from
 * the original set, {@link IImsServiceController#createImsFeature} and
 * the original set, create and {@link IImsServiceController#removeImsFeature} will be called for
 * {@link IImsServiceController#removeImsFeature} will be called for each feature that is
 * each feature that is created/removed.
 * created/removed.
 */
 */
public class ImsServiceController {
public class ImsServiceController {


@@ -74,6 +73,10 @@ public class ImsServiceController {
        @Override
        @Override
        public void binderDied() {
        public void binderDied() {
            Log.e(LOG_TAG, "ImsService(" + mComponentName + ") died. Restarting...");
            Log.e(LOG_TAG, "ImsService(" + mComponentName + ") died. Restarting...");
            synchronized (mLock) {
                mIsBinding = false;
                mIsBound = false;
            }
            notifyAllFeaturesRemoved();
            notifyAllFeaturesRemoved();
            cleanUpService();
            cleanUpService();
            startDelayedRebindToService();
            startDelayedRebindToService();
@@ -98,7 +101,7 @@ public class ImsServiceController {
                        mImsServiceControllerBinder = service;
                        mImsServiceControllerBinder = service;
                        setServiceController(service);
                        setServiceController(service);
                        // create all associated features in the ImsService
                        // create all associated features in the ImsService
                        for (Pair<Integer, Integer> i : mImsFeatures) {
                        for (ImsFeatureConfiguration.FeatureSlotPair i : mImsFeatures) {
                            addImsServiceFeature(i);
                            addImsServiceFeature(i);
                        }
                        }
                    } catch (RemoteException e) {
                    } catch (RemoteException e) {
@@ -120,13 +123,28 @@ public class ImsServiceController {
            synchronized (mLock) {
            synchronized (mLock) {
                mIsBinding = false;
                mIsBinding = false;
            }
            }
            cleanupConnection();
            Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnected. Waiting...");
            // Service disconnected, but we are still technically bound. Waiting for reconnect.
        }

        @Override
        public void onBindingDied(ComponentName name) {
            synchronized (mLock) {
                mIsBinding = false;
                mIsBound = false;
            }
            cleanupConnection();
            Log.w(LOG_TAG, "ImsService(" + name + "): onBindingDied. Starting rebind...");
            startDelayedRebindToService();
        }

        private void cleanupConnection() {
            if (isServiceControllerAvailable()) {
            if (isServiceControllerAvailable()) {
                mImsServiceControllerBinder.unlinkToDeath(mImsDeathRecipient, 0);
                mImsServiceControllerBinder.unlinkToDeath(mImsDeathRecipient, 0);
            }
            }
            notifyAllFeaturesRemoved();
            notifyAllFeaturesRemoved();
            cleanUpService();
            cleanUpService();
            Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnected. Rebinding...");
            startDelayedRebindToService();
        }
        }
    }
    }


@@ -175,7 +193,7 @@ public class ImsServiceController {
    private boolean mIsBound = false;
    private boolean mIsBound = false;
    private boolean mIsBinding = false;
    private boolean mIsBinding = false;
    // Set of a pair of slotId->feature
    // Set of a pair of slotId->feature
    private HashSet<Pair<Integer, Integer>> mImsFeatures;
    private HashSet<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures;
    // Binder interfaces to the features set in mImsFeatures;
    // Binder interfaces to the features set in mImsFeatures;
    private HashSet<ImsFeatureContainer> mImsFeatureBinders = new HashSet<>();
    private HashSet<ImsFeatureContainer> mImsFeatureBinders = new HashSet<>();
    private IImsServiceController mIImsServiceController;
    private IImsServiceController mIImsServiceController;
@@ -315,15 +333,15 @@ public class ImsServiceController {
    }
    }


    /**
    /**
     * Sends request to bind to ImsService designated by the {@ComponentName} with the feature set
     * Sends request to bind to ImsService designated by the {@link ComponentName} with the feature
     * imsFeatureSet
     * set imsFeatureSet.
     *
     *
     * @param imsFeatureSet a Set of Pairs that designate the slotId->featureId that need to be
     * @param imsFeatureSet a Set of Pairs that designate the slotId->featureId that need to be
     *                      created once the service is bound.
     *                      created once the service is bound.
     * @return {@link true} if the service is in the process of being bound, {@link false} if it
     * @return {@link true} if the service is in the process of being bound, {@link false} if it
     * has failed.
     * has failed.
     */
     */
    public boolean bind(HashSet<Pair<Integer, Integer>> imsFeatureSet) {
    public boolean bind(HashSet<ImsFeatureConfiguration.FeatureSlotPair> imsFeatureSet) {
        synchronized (mLock) {
        synchronized (mLock) {
            if (!mIsBound && !mIsBinding) {
            if (!mIsBound && !mIsBinding) {
                mIsBinding = true;
                mIsBinding = true;
@@ -387,26 +405,32 @@ public class ImsServiceController {
     * For every feature that is added, the service calls the associated create. For every
     * For every feature that is added, the service calls the associated create. For every
     * ImsFeature that is removed, {@link IImsServiceController#removeImsFeature} is called.
     * ImsFeature that is removed, {@link IImsServiceController#removeImsFeature} is called.
     */
     */
    public void changeImsServiceFeatures(HashSet<Pair<Integer, Integer>> newImsFeatures)
    public void changeImsServiceFeatures(
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> newImsFeatures)
            throws RemoteException {
            throws RemoteException {
        synchronized (mLock) {
        synchronized (mLock) {
            Log.i(LOG_TAG, "Features changed (" + mImsFeatures + "->" + newImsFeatures + ") for "
                    + "ImsService: " + mComponentName);
            HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldImsFeatures =
                    new HashSet<>(mImsFeatures);
            // Set features first in case we lose binding and need to rebind later.
            mImsFeatures = newImsFeatures;
            if (mIsBound) {
            if (mIsBound) {
                // add features to service.
                // add features to service.
                HashSet<Pair<Integer, Integer>> newFeatures = new HashSet<>(newImsFeatures);
                HashSet<ImsFeatureConfiguration.FeatureSlotPair> newFeatures =
                newFeatures.removeAll(mImsFeatures);
                        new HashSet<>(mImsFeatures);
                for (Pair<Integer, Integer> i : newFeatures) {
                newFeatures.removeAll(oldImsFeatures);
                for (ImsFeatureConfiguration.FeatureSlotPair i : newFeatures) {
                    addImsServiceFeature(i);
                    addImsServiceFeature(i);
                }
                }
                // remove old features
                // remove old features
                HashSet<Pair<Integer, Integer>> oldFeatures = new HashSet<>(mImsFeatures);
                HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldFeatures =
                oldFeatures.removeAll(newImsFeatures);
                        new HashSet<>(oldImsFeatures);
                for (Pair<Integer, Integer> i : oldFeatures) {
                oldFeatures.removeAll(mImsFeatures);
                for (ImsFeatureConfiguration.FeatureSlotPair i : oldFeatures) {
                    removeImsServiceFeature(i);
                    removeImsServiceFeature(i);
                }
                }
            }
            }
            Log.i(LOG_TAG, "Features changed (" + mImsFeatures + "->" + newImsFeatures + ") for "
                    + "ImsService: " + mComponentName);
            mImsFeatures = newImsFeatures;
        }
        }
    }
    }


@@ -464,7 +488,11 @@ public class ImsServiceController {


    public void enableIms(int slotId) {
    public void enableIms(int slotId) {
        try {
        try {
            synchronized (mLock) {
                if (isServiceControllerAvailable()) {
                    mIImsServiceController.enableIms(slotId);
                    mIImsServiceController.enableIms(slotId);
                }
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.w(LOG_TAG, "Couldn't enable IMS: " + e.getMessage());
            Log.w(LOG_TAG, "Couldn't enable IMS: " + e.getMessage());
        }
        }
@@ -472,7 +500,11 @@ public class ImsServiceController {


    public void disableIms(int slotId) {
    public void disableIms(int slotId) {
        try {
        try {
            synchronized (mLock) {
                if (isServiceControllerAvailable()) {
                    mIImsServiceController.disableIms(slotId);
                    mIImsServiceController.disableIms(slotId);
                }
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.w(LOG_TAG, "Couldn't disable IMS: " + e.getMessage());
            Log.w(LOG_TAG, "Couldn't disable IMS: " + e.getMessage());
        }
        }
@@ -512,7 +544,8 @@ public class ImsServiceController {
     */
     */
    public IImsRegistration getRegistration(int slotId) throws RemoteException {
    public IImsRegistration getRegistration(int slotId) throws RemoteException {
        synchronized (mLock) {
        synchronized (mLock) {
            return mIImsServiceController.getRegistration(slotId);
            return isServiceControllerAvailable()
                    ? mIImsServiceController.getRegistration(slotId) : null;
        }
        }
    }
    }


@@ -521,7 +554,7 @@ public class ImsServiceController {
     */
     */
    public IImsConfig getConfig(int slotId) throws RemoteException {
    public IImsConfig getConfig(int slotId) throws RemoteException {
        synchronized (mLock) {
        synchronized (mLock) {
            return mIImsServiceController.getConfig(slotId);
            return isServiceControllerAvailable() ? mIImsServiceController.getConfig(slotId) : null;
        }
        }
    }
    }


@@ -537,6 +570,15 @@ public class ImsServiceController {
        mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController);
        mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController);
    }
    }


    /**
     * @return true if the controller is currently bound.
     */
    public boolean isBound() {
        synchronized (mLock) {
            return mIsBound;
        }
    }

    /**
    /**
     * Check to see if the service controller is available, overridden for compat versions,
     * Check to see if the service controller is available, overridden for compat versions,
     * @return true if available, false otherwise;
     * @return true if available, false otherwise;
@@ -623,46 +665,48 @@ public class ImsServiceController {
    }
    }


    // This method should only be called when synchronized on mLock
    // This method should only be called when synchronized on mLock
    private void addImsServiceFeature(Pair<Integer, Integer> featurePair) throws RemoteException {
    private void addImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair)
            throws RemoteException {
        if (!isServiceControllerAvailable() || mCallbacks == null) {
        if (!isServiceControllerAvailable() || mCallbacks == null) {
            Log.w(LOG_TAG, "addImsServiceFeature called with null values.");
            Log.w(LOG_TAG, "addImsServiceFeature called with null values.");
            return;
            return;
        }
        }
        ImsFeatureStatusCallback c = new ImsFeatureStatusCallback(featurePair.first,
        ImsFeatureStatusCallback c = new ImsFeatureStatusCallback(featurePair.slotId,
                featurePair.second);
                featurePair.featureType);
        mFeatureStatusCallbacks.add(c);
        mFeatureStatusCallbacks.add(c);
        IInterface f = createImsFeature(featurePair.first, featurePair.second, c.getCallback());
        IInterface f = createImsFeature(featurePair.slotId, featurePair.featureType,
        addImsFeatureBinder(featurePair.first, featurePair.second, f);
                c.getCallback());
        addImsFeatureBinder(featurePair.slotId, featurePair.featureType, f);
        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
        mCallbacks.imsServiceFeatureCreated(featurePair.first, featurePair.second, this);
        mCallbacks.imsServiceFeatureCreated(featurePair.slotId, featurePair.featureType, this);
        // Send callback to ImsServiceProxy to change supported ImsFeatures
        // Send callback to ImsServiceProxy to change supported ImsFeatures
        sendImsFeatureCreatedCallback(featurePair.first, featurePair.second);
        sendImsFeatureCreatedCallback(featurePair.slotId, featurePair.featureType);
    }
    }


    // This method should only be called when synchronized on mLock
    // This method should only be called when synchronized on mLock
    private void removeImsServiceFeature(Pair<Integer, Integer> featurePair)
    private void removeImsServiceFeature(ImsFeatureConfiguration.FeatureSlotPair featurePair)
            throws RemoteException {
            throws RemoteException {
        if (!isServiceControllerAvailable() || mCallbacks == null) {
        if (!isServiceControllerAvailable() || mCallbacks == null) {
            Log.w(LOG_TAG, "removeImsServiceFeature called with null values.");
            Log.w(LOG_TAG, "removeImsServiceFeature called with null values.");
            return;
            return;
        }
        }
        ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c ->
        ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c ->
                c.mSlotId == featurePair.first && c.mFeatureType == featurePair.second)
                c.mSlotId == featurePair.slotId && c.mFeatureType == featurePair.featureType)
                .findFirst().orElse(null);
                .findFirst().orElse(null);
        // Remove status callbacks from list.
        // Remove status callbacks from list.
        if (callbackToRemove != null) {
        if (callbackToRemove != null) {
            mFeatureStatusCallbacks.remove(callbackToRemove);
            mFeatureStatusCallbacks.remove(callbackToRemove);
        }
        }
        removeImsFeature(featurePair.first, featurePair.second,
        removeImsFeature(featurePair.slotId, featurePair.featureType,
                (callbackToRemove != null ? callbackToRemove.getCallback() : null));
                (callbackToRemove != null ? callbackToRemove.getCallback() : null));
        removeImsFeatureBinder(featurePair.first, featurePair.second);
        removeImsFeatureBinder(featurePair.slotId, featurePair.featureType);
        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
        // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
        mCallbacks.imsServiceFeatureRemoved(featurePair.first, featurePair.second, this);
        mCallbacks.imsServiceFeatureRemoved(featurePair.slotId, featurePair.featureType, this);
        // Send callback to ImsServiceProxy to change supported ImsFeatures
        // Send callback to ImsServiceProxy to change supported ImsFeatures
        // Ensure that ImsServiceProxy callback occurs after ImsResolver callback. If an
        // Ensure that ImsServiceProxy callback occurs after ImsResolver callback. If an
        // ImsManager requests the ImsService while it is being removed in ImsResolver, this
        // ImsManager requests the ImsService while it is being removed in ImsResolver, this
        // callback will clean it up after.
        // callback will clean it up after.
        sendImsFeatureRemovedCallback(featurePair.first, featurePair.second);
        sendImsFeatureRemovedCallback(featurePair.slotId, featurePair.featureType);
    }
    }


    // This method should only be called when already synchronized on mLock.
    // This method should only be called when already synchronized on mLock.
@@ -714,9 +758,9 @@ public class ImsServiceController {
            return;
            return;
        }
        }
        synchronized (mLock) {
        synchronized (mLock) {
            for (Pair<Integer, Integer> feature : mImsFeatures) {
            for (ImsFeatureConfiguration.FeatureSlotPair feature : mImsFeatures) {
                mCallbacks.imsServiceFeatureRemoved(feature.first, feature.second, this);
                mCallbacks.imsServiceFeatureRemoved(feature.slotId, feature.featureType, this);
                sendImsFeatureRemovedCallback(feature.first, feature.second);
                sendImsFeatureRemovedCallback(feature.slotId, feature.featureType);
            }
            }
        }
        }
    }
    }
@@ -727,7 +771,6 @@ public class ImsServiceController {
            mImsServiceConnection = null;
            mImsServiceConnection = null;
            mImsServiceControllerBinder = null;
            mImsServiceControllerBinder = null;
            setServiceController(null);
            setServiceController(null);
            mIsBound = false;
        }
        }
    }
    }
}
}
+160 −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 com.android.internal.telephony.ims;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.util.Log;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Manages the querying of multiple ImsServices asynchronously in order to retrieve the ImsFeatures
 * they support.
 */

public class ImsServiceFeatureQueryManager {

    private final class ImsServiceFeatureQuery implements ServiceConnection {

        private static final String LOG_TAG = "ImsServiceFeatureQuery";

        private final ComponentName mName;
        private final String mIntentFilter;

        ImsServiceFeatureQuery(ComponentName name, String intentFilter) {
            mName = name;
            mIntentFilter = intentFilter;
        }

        /**
         * Starts the bind to the ImsService specified ComponentName.
         * @return true if binding started, false if it failed and will not recover.
         */
        public boolean start() {
            Log.d(LOG_TAG, "start: intent filter=" + mIntentFilter + ", name=" + mName);
            Intent imsServiceIntent = new Intent(mIntentFilter).setComponent(mName);
            int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                    | Context.BIND_IMPORTANT;
            boolean bindStarted = mContext.bindService(imsServiceIntent, this, serviceFlags);
            if (!bindStarted) {
                // Docs say to unbind if this fails.
                cleanup();
            }
            return bindStarted;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(LOG_TAG, "onServiceConnected for component: " + name);
            if (service != null) {
                queryImsFeatures(IImsServiceController.Stub.asInterface(service));
            } else {
                Log.w(LOG_TAG, "onServiceConnected: " + name + " binder null, cleaning up.");
                cleanup();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.w(LOG_TAG, "onServiceDisconnected for component: " + name);
        }

        private void queryImsFeatures(IImsServiceController controller) {
            ImsFeatureConfiguration config;
            try {
                config = controller.querySupportedImsFeatures();
            } catch (RemoteException e) {
                Log.w(LOG_TAG, "queryImsFeatures - error: " + e);
                cleanup();
                mListener.onError(mName);
                return;
            }
            Set<ImsFeatureConfiguration.FeatureSlotPair> servicePairs = config.getServiceFeatures();
            // Complete, remove from active queries and notify.
            cleanup();
            mListener.onComplete(mName, servicePairs);
        }

        private void cleanup() {
            mContext.unbindService(this);
            synchronized (mLock) {
                mActiveQueries.remove(mName);
            }
        }
    }

    public interface Listener {
        /**
         * Called when a query has completed.
         * @param name The Package Name of the query
         * @param features A Set of slotid->feature pairs that the ImsService supports.
         */
        void onComplete(ComponentName name, Set<ImsFeatureConfiguration.FeatureSlotPair> features);

        /**
         * Called when a query has failed and should be retried.
         */
        void onError(ComponentName name);
    }

    // Maps an active ImsService query (by Package Name String) its query.
    private final Map<ComponentName, ImsServiceFeatureQuery> mActiveQueries = new HashMap<>();
    private final Context mContext;
    private final Listener mListener;
    private final Object mLock = new Object();

    public ImsServiceFeatureQueryManager(Context context, Listener listener) {
        mContext = context;
        mListener = listener;
    }

    /**
     * Starts an ImsService feature query for the ComponentName and Intent specified.
     * @param name The ComponentName of the ImsService being queried.
     * @param intentFilter The Intent filter that the ImsService specified.
     * @return true if the query started, false if it was unable to start.
     */
    public boolean startQuery(ComponentName name, String intentFilter) {
        synchronized (mLock) {
            if (mActiveQueries.containsKey(name)) {
                // We already have an active query, wait for it to return.
                return true;
            }
            ImsServiceFeatureQuery query = new ImsServiceFeatureQuery(name, intentFilter);
            mActiveQueries.put(name, query);
            return query.start();
        }
    }

    /**
     * @return true if there are any active queries, false if the manager is idle.
     */
    public boolean isQueryInProgress() {
        synchronized (mLock) {
            return !mActiveQueries.isEmpty();
        }
    }
}
+13 −10
Original line number Original line Diff line number Diff line
@@ -68,8 +68,8 @@ public class ImsRegistrationTests {
    @Test
    @Test
    public void testRegistrationConfigParcel() {
    public void testRegistrationConfigParcel() {
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration.Builder()
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration.Builder()
                .addFeature(ImsFeature.FEATURE_MMTEL)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_MMTEL)
                .addFeature(ImsFeature.FEATURE_RCS)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_RCS)
                .build();
                .build();
        Parcel p = Parcel.obtain();
        Parcel p = Parcel.obtain();
        testConfig.writeToParcel(p, 0);
        testConfig.writeToParcel(p, 0);
@@ -85,14 +85,14 @@ public class ImsRegistrationTests {
    @Test
    @Test
    public void testRegistrationConfigPermutationEqual() {
    public void testRegistrationConfigPermutationEqual() {
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration.Builder()
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration.Builder()
                .addFeature(ImsFeature.FEATURE_MMTEL)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_MMTEL)
                .addFeature(ImsFeature.FEATURE_RCS)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_RCS)
                .build();
                .build();


        // Permute field insertion ordering to ensure order doesn't matter.
        // Permute field insertion ordering to ensure order doesn't matter.
        ImsFeatureConfiguration testConfig2 = new ImsFeatureConfiguration.Builder()
        ImsFeatureConfiguration testConfig2 = new ImsFeatureConfiguration.Builder()
                .addFeature(ImsFeature.FEATURE_RCS)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_RCS)
                .addFeature(ImsFeature.FEATURE_MMTEL)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_MMTEL)
                .build();
                .build();


        assertEquals(testConfig, testConfig2);
        assertEquals(testConfig, testConfig2);
@@ -101,13 +101,16 @@ public class ImsRegistrationTests {
    @SmallTest
    @SmallTest
    @Test
    @Test
    public void testRegistrationConfigConstructorsEqual() {
    public void testRegistrationConfigConstructorsEqual() {
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration(
        // Permute field insertion ordering to ensure order doesn't matter.
                new int[] {ImsFeature.FEATURE_MMTEL, ImsFeature.FEATURE_RCS});
        ImsFeatureConfiguration testConfig = new ImsFeatureConfiguration.Builder()
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_MMTEL)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_RCS)
                .build();


        // Permute field insertion ordering to ensure order doesn't matter.
        // Permute field insertion ordering to ensure order doesn't matter.
        ImsFeatureConfiguration testConfig2 = new ImsFeatureConfiguration.Builder()
        ImsFeatureConfiguration testConfig2 = new ImsFeatureConfiguration.Builder()
                .addFeature(ImsFeature.FEATURE_RCS)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_RCS)
                .addFeature(ImsFeature.FEATURE_MMTEL)
                .addFeature(/*slotId*/ 0, ImsFeature.FEATURE_MMTEL)
                .build();
                .build();


        assertEquals(testConfig, testConfig2);
        assertEquals(testConfig, testConfig2);
Loading