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

Commit e92de7b0 authored by Daniel Bright's avatar Daniel Bright Committed by Automerger Merge Worker
Browse files

Merge "Fully support dynamic ims device features" am: 831d0ba3

Change-Id: Icbe8e4c3cf0254aebd11c6e45f76aff55fff0dcc
parents 4efca3f9 831d0ba3
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: