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

Commit 831d0ba3 authored by Daniel Bright's avatar Daniel Bright Committed by Gerrit Code Review
Browse files

Merge "Fully support dynamic ims device features"

parents 98f5c24b dc89d725
Loading
Loading
Loading
Loading
+53 −7
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.Message;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -405,6 +406,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
    // Persistent Logging
    private final LocalLog mEventLog = new LocalLog(50);

    private boolean mBootCompletedHandlerRan = false;

    // Synchronize all events on a handler to ensure that the cache includes the most recent
    // version of the installed ImsServices.
    private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> {
@@ -420,9 +423,12 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
                break;
            }
            case HANDLER_BOOT_COMPLETE: {
                if (!mBootCompletedHandlerRan) {
                    mBootCompletedHandlerRan = true;
                    mEventLog.log("handling BOOT_COMPLETE");
                    // Re-evaluate bound services for all slots after requerying packagemanager
                    maybeAddedImsService(null /*packageName*/);
                }
                break;
            }
            case HANDLER_CONFIG_CHANGED: {
@@ -539,8 +545,17 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
        mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter);
        mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter(
                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));

        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        if (userManager.isUserUnlocked()) {
            mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget();
        } else {
            mReceiverContext.registerReceiver(mBootCompleted, new IntentFilter(
                    Intent.ACTION_BOOT_COMPLETED));
            if (userManager.isUserUnlocked()) {
                mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget();
            }
        }
    }

    @VisibleForTesting
@@ -1179,6 +1194,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal

    // Called from handler ONLY.
    private void carrierConfigChanged(int slotId) {
        updateBoundDeviceServices();

        if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
            // not specified, update carrier override cache and possibly rebind on all slots.
            for (int i = 0; i < mNumSlots; i++) {
@@ -1188,11 +1205,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
        updateBoundServices(slotId, getImsPackageOverrideConfig(slotId));
    }

    private void updateBoundDeviceServices() {
        Log.d(TAG, "updateBoundDeviceServices: called");
        ArrayMap<String, ImsServiceInfo> featureDynamicImsPackages = new ArrayMap<>();
        for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) {
            String packageName = getDeviceConfiguration(f);
            ImsServiceInfo serviceInfo = getImsServiceInfoFromCache(packageName);
            if (serviceInfo != null && !serviceInfo.featureFromMetadata
                    && !featureDynamicImsPackages.containsKey(packageName)) {
                featureDynamicImsPackages.put(packageName, serviceInfo);

                Log.d(TAG, "updateBoundDeviceServices: Schedule query for package=" + packageName);
                scheduleQueryForFeatures(featureDynamicImsPackages.get(packageName));
            }
        }
    }

    private void updateBoundServices(int slotId, Map<Integer, String> featureMap) {
        if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlots) {
            return;
        }
        boolean hasConfigChanged = false;
        boolean didQuerySchedule = false;
        for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) {
            String overridePackageName = getOverridePackageName(slotId, f);
            String oldPackageName = getCarrierConfiguredPackageName(slotId, f);
@@ -1207,20 +1241,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
                        ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid"), slotId));
                newPackageName = overridePackageName;
            }
            mEventLog.log("updateBoundServices - carrier package changed: "
                    + oldPackageName + " -> " + newPackageName + " on slot " + slotId);

            setCarrierConfiguredPackageName(newPackageName, slotId, f);
            // Carrier config may have not changed, but we still want to kick off a recalculation
            // in case there has been a change to the supported device features.
            ImsServiceInfo info = getImsServiceInfoFromCache(newPackageName);
            mEventLog.log("updateBoundServices - carrier package changed: "
                    + oldPackageName + " -> " + newPackageName + " on slot " + slotId
                    + ", hasConfigChanged=" + hasConfigChanged);
            if (info == null || info.featureFromMetadata) {
                hasConfigChanged = true;
            } else {
                // Config will change when this query completes
                scheduleQueryForFeatures(info);
                didQuerySchedule = true;
            }
        }
        if (hasConfigChanged) calculateFeatureConfigurationChange();

        if (hasConfigChanged && didQuerySchedule) {
            mEventLog.log("[warning] updateBoundServices - both hasConfigChange and query "
                    + "scheduled on slot " + slotId);
        }
    }

    private @NonNull Map<Integer, String> getImsPackageOverrideConfig(int slotId) {
@@ -1384,6 +1426,10 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal
        service.replaceFeatures(features);
        // Wait until all queries have completed before changing the configuration to reduce churn.
        if (!mFeatureQueryManager.isQueryInProgress()) {
            if (mHandler.hasMessages(HANDLER_DYNAMIC_FEATURE_CHANGE)) {
                mEventLog.log("[warning] dynamicQueryComplete - HANDLER_DYNAMIC_FEATURE_CHANGE "
                        + "pending with calculateFeatureConfigurationChange()");
            }
            calculateFeatureConfigurationChange();
        }
    }
+88 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserManager;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsService;
@@ -54,6 +55,7 @@ import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.internal.telephony.PhoneConfigurationManager;
@@ -68,6 +70,7 @@ import org.mockito.Mock;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -89,6 +92,7 @@ public class ImsResolverTest extends ImsTestBase {
            "TestCarrier2Pkg", "Carrier2ImsService");

    private static final int NUM_MAX_SLOTS = 2;
    private static final String TAG = ImsResolverTest.class.getSimpleName();

    @Mock
    Context mMockContext;
@@ -101,6 +105,8 @@ public class ImsResolverTest extends ImsTestBase {
    @Mock
    CarrierConfigManager mMockCarrierConfigManager;
    @Mock
    UserManager mMockUserManager;
    @Mock
    ImsResolver.ImsDynamicQueryManagerFactory mMockQueryManagerFactory;
    @Mock
    ImsServiceFeatureQueryManager mMockQueryManager;
@@ -549,6 +555,61 @@ public class ImsResolverTest extends ImsTestBase {
        verify(controller, never()).unbind();
    }

    /**
     * Test that the dynamic ims services are bound in the event that the user is not yet unlocked
     * but the carrier config changed event is fired.
     * @throws RemoteException
     */
    @Test
    @SmallTest
    public void testDeviceDynamicQueryBindsOnCarrierConfigChanged() throws RemoteException {
        //Set package names with no features set in metadata
        List<ResolveInfo> info = new ArrayList<>();
        info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, new HashSet<>(), true));
        info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, new HashSet<>(), true));
        info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true));
        setupPackageQuery(info);

        //setupResolver
        setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(),
                TEST_DEVICE2_DEFAULT_NAME.getPackageName());

        //Set controllers
        ImsServiceController deviceController = mock(ImsServiceController.class);
        ImsServiceController deviceController2 = mock(ImsServiceController.class);
        ImsServiceController carrierController = mock(ImsServiceController.class);

        Map<String, ImsServiceController> controllerMap = new ArrayMap<>();
        controllerMap.put(TEST_DEVICE_DEFAULT_NAME.getPackageName(), deviceController);
        controllerMap.put(TEST_DEVICE2_DEFAULT_NAME.getPackageName(), deviceController2);
        controllerMap.put(TEST_CARRIER_DEFAULT_NAME.getPackageName(), carrierController);
        setImsServiceControllerFactory(controllerMap);

        //Set features to device ims services
        Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures1 =
                convertToFeatureSlotPairs(0, ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE,
                        ImsResolver.METADATA_MMTEL_FEATURE);

        Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures2 =
                convertToFeatureSlotPairs(0, ImsResolver.METADATA_RCS_FEATURE);

        startBindNoCarrierConfig(1);
        mLooper.processAllMessages();
        // ensure that startQuery was called
        verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE_DEFAULT_NAME),
                any(String.class));

        verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE2_DEFAULT_NAME),
                any(String.class));

        mDynamicQueryListener.onComplete(TEST_DEVICE_DEFAULT_NAME, deviceFeatures1);
        mDynamicQueryListener.onComplete(TEST_DEVICE2_DEFAULT_NAME, deviceFeatures2);
        mLooper.processAllMessages();

        verify(deviceController, times(2)).bind(eq(deviceFeatures1));
        verify(deviceController2, times(1)).bind(eq(deviceFeatures2));
    }

    /**
     * Test that when a device and carrier override package are set, both ImsServices are bound.
     * Verify that the carrier ImsService features are created and the device default features
@@ -1581,6 +1642,12 @@ public class ImsResolverTest extends ImsTestBase {
        when(mMockContext.createContextAsUser(any(), eq(0))).thenReturn(mMockContext);
        when(mMockContext.getSystemService(eq(Context.CARRIER_CONFIG_SERVICE))).thenReturn(
                mMockCarrierConfigManager);
        when(mMockContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mMockUserManager);

        //If this is not false, then HANDLER_BOOT_COMPLETE is fired now but the controller factories
        //used in the test methods aren't created in time.
        when(mMockUserManager.isUserUnlocked()).thenReturn(false);

        // Support configs for MSIM always in case we are testing dynamic sim slot config changes.
        mCarrierConfigs = new PersistableBundle[NUM_MAX_SLOTS];
        for (int i = 0; i < NUM_MAX_SLOTS; i++) {
@@ -1719,6 +1786,22 @@ public class ImsResolverTest extends ImsTestBase {
        mLooper.processAllMessages();
    }

    private void setImsServiceControllerFactory(Map<String, ImsServiceController> controllerMap) {
        mTestImsResolver.setImsServiceControllerFactory(
                new ImsResolver.ImsServiceControllerFactory() {
                    @Override
                    public String getServiceInterface() {
                        return ImsService.SERVICE_INTERFACE;
                    }

                    @Override
                    public ImsServiceController create(Context context, ComponentName componentName,
                            ImsServiceController.ImsServiceControllerCallbacks callbacks) {
                        return controllerMap.get(componentName.getPackageName());
                    }
                });
    }

    private void setImsServiceControllerFactory(ImsServiceController deviceController,
            ImsServiceController carrierController) {
        mTestImsResolver.setImsServiceControllerFactory(
@@ -1844,6 +1927,11 @@ public class ImsResolverTest extends ImsTestBase {
                .collect(Collectors.toCollection(HashSet::new));
    }

    private HashSet<ImsFeatureConfiguration.FeatureSlotPair> convertToFeatureSlotPairs(
            int slotId, String... features) {
        return convertToHashSet(new ArraySet<>(features), slotId);
    }

    private int metadataStringToFeature(String f) {
        switch (f) {
            case ImsResolver.METADATA_MMTEL_FEATURE: