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

Commit e920eb4a authored by Malcolm Chen's avatar Malcolm Chen
Browse files

Adding logic in MultiSimSettingController to pop SIM selection dialog.

Bug: 128645056
Test: manual - In dsds mode, remove default SIM from two active SIMs;
insert another SIM when one is present; switching between eSIM profiles.

Change-Id: Idea54e5e24b632392cbba4421c6a59768b3127b5
Merged-In: Idea54e5e24b632392cbba4421c6a59768b3127b5
parent d337ba5e
Loading
Loading
Loading
Loading
+90 −19
Original line number Original line Diff line number Diff line
@@ -16,7 +16,16 @@


package com.android.internal.telephony;
package com.android.internal.telephony;


import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_ID;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_FOR_ALL_TYPES;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;

import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Settings.SettingNotFoundException;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionInfo;
@@ -39,13 +48,14 @@ import java.util.stream.Collectors;
 * 3) For primary subscriptions, only default data subscription will have MOBILE_DATA on.
 * 3) For primary subscriptions, only default data subscription will have MOBILE_DATA on.
 */
 */
public class MultiSimSettingController {
public class MultiSimSettingController {
    static final String LOG_TAG = "MultiSimSettingController";
    private static final String LOG_TAG = "MultiSimSettingController";
    static final boolean DBG = true;
    private static final boolean DBG = true;


    private final Context mContext;
    private final Context mContext;
    private final Phone[] mPhones;
    private final Phone[] mPhones;
    private final SubscriptionController mSubController;
    private final SubscriptionController mSubController;
    private boolean mIsAllSubscriptionsLoaded;
    private boolean mIsAllSubscriptionsLoaded;
    private List<SubscriptionInfo> mPrimarySubList;


    /** The singleton instance. */
    /** The singleton instance. */
    private static MultiSimSettingController sInstance = null;
    private static MultiSimSettingController sInstance = null;
@@ -136,7 +146,7 @@ public class MultiSimSettingController {
        if (DBG) log("onSubscriptionGroupCreated");
        if (DBG) log("onSubscriptionGroupCreated");
        if (subGroup == null || subGroup.length == 0) return;
        if (subGroup == null || subGroup.length == 0) return;


        // Get a referece subscription from which all subscriptions in the group will copy settings.
        // Get a reference subscription to copy settings from.
        // TODO: the reference sub should be passed in from external caller.
        // TODO: the reference sub should be passed in from external caller.
        int refSubId = subGroup[0];
        int refSubId = subGroup[0];
        for (int subId : subGroup) {
        for (int subId : subGroup) {
@@ -177,35 +187,95 @@ public class MultiSimSettingController {
     *    not a user settable value anymore.
     *    not a user settable value anymore.
     * 4) If non above is met, clear the default value to INVALID.
     * 4) If non above is met, clear the default value to INVALID.
     */
     */
    @VisibleForTesting
    public synchronized void updateDefaults() {
    public synchronized void updateDefaults() {
        if (DBG) log("updateDefaults");
        if (DBG) log("updateDefaults");
        List<SubscriptionInfo> subInfos = mSubController

        if (!mIsAllSubscriptionsLoaded) return;

        List<SubscriptionInfo> activeSubInfos = mSubController
                .getActiveSubscriptionInfoList(mContext.getOpPackageName());
                .getActiveSubscriptionInfoList(mContext.getOpPackageName());
        // If subscription controller is not ready, do nothing.
        // If subscription controller is not ready, do nothing.
        if (subInfos == null) return;
        if (activeSubInfos == null) return;

        List<SubscriptionInfo> prevPrimarySubList = mPrimarySubList;


        // Opportunistic subscriptions can't be default data / voice / sms subscription.
        // Opportunistic subscriptions can't be default data / voice / sms subscription.
        subInfos = subInfos.stream()
        mPrimarySubList = activeSubInfos.stream().filter(info -> !info.isOpportunistic())
                .filter(info -> !info.isOpportunistic())
                .collect(Collectors.toList());
                .collect(Collectors.toList());


        if (DBG) log("[updateDefaultValues] records: " + subInfos);
        // If there's only one primary subscription active, we trigger PREFERRED_PICK_DIALOG
        // dialog if and only if there were multiple primary SIM cards and one is removed.
        // Otherwise, if user just inserted their first SIM, or there's one primary and one
        // opportunistic subscription active (activeSubInfos.size() > 1), we automatically
        // set the primary to be default SIM and return.
        if (mPrimarySubList.size() == 1 && (activeSubInfos.size() > 1
                || (prevPrimarySubList != null && prevPrimarySubList.isEmpty()))) {
            int subId = mPrimarySubList.get(0).getSubscriptionId();
            if (DBG) log("[updateDefaultValues] to only primary sub " + subId);
            mSubController.setDefaultDataSubId(subId);
            mSubController.setDefaultVoiceSubId(subId);
            mSubController.setDefaultSmsSubId(subId);
            return;
        }

        if (DBG) log("[updateDefaultValues] records: " + mPrimarySubList);


        // TODO: b/121394765 update logic once confirmed the behaviors.
        // TODO: b/121394765 update logic once confirmed the behaviors.
        // Update default data subscription.
        // Update default data subscription.
        if (DBG) log("[updateDefaultValues] Update default data subscription");
        if (DBG) log("[updateDefaultValues] Update default data subscription");
        updateDefaultValue(subInfos, mSubController.getDefaultDataSubId(), true, true,
        boolean dataSelected = updateDefaultValue(mPrimarySubList,
                mSubController.getDefaultDataSubId(),
                (newValue -> mSubController.setDefaultDataSubId(newValue)));
                (newValue -> mSubController.setDefaultDataSubId(newValue)));


        // Update default voice subscription.
        // Update default voice subscription.
        if (DBG) log("[updateDefaultValues] Update default voice subscription");
        if (DBG) log("[updateDefaultValues] Update default voice subscription");
        updateDefaultValue(subInfos, mSubController.getDefaultVoiceSubId(), true, false,
        boolean voiceSelected = updateDefaultValue(mPrimarySubList,
                mSubController.getDefaultVoiceSubId(),
                (newValue -> mSubController.setDefaultVoiceSubId(newValue)));
                (newValue -> mSubController.setDefaultVoiceSubId(newValue)));


        // Update default sms subscription.
        // Update default sms subscription.
        if (DBG) log("[updateDefaultValues] Update default sms subscription");
        if (DBG) log("[updateDefaultValues] Update default sms subscription");
        updateDefaultValue(subInfos, mSubController.getDefaultSmsSubId(), true, false,
        boolean smsSelected = updateDefaultValue(mPrimarySubList,
                mSubController.getDefaultSmsSubId(),
                (newValue -> mSubController.setDefaultSmsSubId(newValue)));
                (newValue -> mSubController.setDefaultSmsSubId(newValue)));

        showSimSelectDialogIfNeeded(prevPrimarySubList, dataSelected, voiceSelected, smsSelected);
    }

    private void showSimSelectDialogIfNeeded(List<SubscriptionInfo> prevPrimarySubs,
            boolean dataSelected, boolean voiceSelected, boolean smsSelected) {
        int dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;
        int preferredSubId = INVALID_SUBSCRIPTION_ID;
        boolean primarySubRemoved = prevPrimarySubs != null
                && mPrimarySubList.size() < prevPrimarySubs.size();
        boolean primarySubAdded = prevPrimarySubs != null
                && mPrimarySubList.size() > prevPrimarySubs.size();

        // If a primary subscription is removed and only one is left active, ask user
        // for preferred sub selection if any default setting is not set.
        // If another primary subscription is added or default data is not selected, ask
        // user to select default for data as it's most important.
        if (mPrimarySubList.size() == 1 && primarySubRemoved
                && (!dataSelected || !smsSelected || !voiceSelected)) {
            dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_FOR_ALL_TYPES;
            preferredSubId = mPrimarySubList.get(0).getSubscriptionId();
        } else if (mPrimarySubList.size() > 1 && (!dataSelected || primarySubAdded)) {
            dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
        }

        if (dialogType != EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE) {
            Intent intent = new Intent();
            intent.setAction(ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED);
            intent.setClassName("com.android.settings",
                    "com.android.settings.sim.SimSelectNotification");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, dialogType);
            if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_FOR_ALL_TYPES) {
                intent.putExtra(EXTRA_DEFAULT_SUBSCRIPTION_ID, preferredSubId);
            }
            mContext.sendBroadcast(intent);
        }
    }
    }


    private void disableDataForNonDefaultNonOpportunisticSubscriptions() {
    private void disableDataForNonDefaultNonOpportunisticSubscriptions() {
@@ -298,13 +368,12 @@ public class MultiSimSettingController {
        void update(int newValue);
        void update(int newValue);
    }
    }


    private void updateDefaultValue(List<SubscriptionInfo> subInfos, int oldValue,
    // Returns whether the new default value is valid.
            boolean inheritWithinGroup, boolean setToOnlyCandidate, UpdateDefaultAction action) {
    private boolean updateDefaultValue(List<SubscriptionInfo> subInfos, int oldValue,
        int newValue = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
            UpdateDefaultAction action) {
        int newValue = INVALID_SUBSCRIPTION_ID;


        if (subInfos.size() == 1 && setToOnlyCandidate) {
        if (subInfos.size() > 0) {
            newValue = subInfos.get(0).getSubscriptionId();
        } else if (subInfos.size() > 0) {
            // Get groupUuid of old
            // Get groupUuid of old
            String groupUuid = getGroupUuid(oldValue);
            String groupUuid = getGroupUuid(oldValue);


@@ -313,8 +382,8 @@ public class MultiSimSettingController {
                if (DBG) log("[updateDefaultValue] Record.id: " + id);
                if (DBG) log("[updateDefaultValue] Record.id: " + id);
                // If the old subId is still active, or there's another active primary subscription
                // If the old subId is still active, or there's another active primary subscription
                // that is in the same group, that should become the new default subscription.
                // that is in the same group, that should become the new default subscription.
                if (id == oldValue || (groupUuid != null && groupUuid.equals(info.getGroupUuid())
                if (id == oldValue || (groupUuid != null && groupUuid.equals(
                        && inheritWithinGroup)) {
                        info.getGroupUuid()))) {
                    log("[updateDefaultValue] updates to subId=" + id);
                    log("[updateDefaultValue] updates to subId=" + id);
                    newValue = id;
                    newValue = id;
                    break;
                    break;
@@ -326,6 +395,8 @@ public class MultiSimSettingController {
            if (DBG) log("[updateDefaultValue: subId] from " + oldValue + " to " + newValue);
            if (DBG) log("[updateDefaultValue: subId] from " + oldValue + " to " + newValue);
            action.update(newValue);
            action.update(newValue);
        }
        }

        return SubscriptionManager.isValidSubscriptionId(newValue);
    }
    }


    private void log(String msg) {
    private void log(String msg) {
+0 −13
Original line number Original line Diff line number Diff line
@@ -2167,19 +2167,6 @@ public class SubscriptionController extends ISub.Stub {
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }
    }


    @Override
    public void clearDefaultsForInactiveSubIds() {
        enforceModifyPhoneState("clearDefaultsForInactiveSubIds");

        // Now that all security checks passes, perform the operation as ourselves.
        final long identity = Binder.clearCallingIdentity();
        try {
            MultiSimSettingController.getInstance().updateDefaults();
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
    /**
     * Whether a subscription is opportunistic or not.
     * Whether a subscription is opportunistic or not.
     */
     */
+3 −0
Original line number Original line Diff line number Diff line
@@ -508,6 +508,9 @@ public class ContextFixture implements TestFixture<Context> {
        public Context getApplicationContext() {
        public Context getApplicationContext() {
            return null;
            return null;
        }
        }

        @Override
        public void startActivity(Intent intent) {}
    }
    }


    private final Multimap<String, ComponentName> mComponentNamesByAction =
    private final Multimap<String, ComponentName> mComponentNamesByAction =
+1 −1
Original line number Original line Diff line number Diff line
@@ -154,7 +154,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
        List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo2);
        List<SubscriptionInfo> infoList = Arrays.asList(mSubInfo2);
        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
        doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString());
        mMultiSimSettingControllerUT.updateDefaults();
        mMultiSimSettingControllerUT.updateDefaults();
        verify(mSubControllerMock).setDefaultDataSubId(2);
        verify(mSubControllerMock).setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        verify(mSubControllerMock).setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        verify(mSubControllerMock).setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt());
        verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt());
    }
    }
+0 −4
Original line number Original line Diff line number Diff line
@@ -251,10 +251,6 @@ public class SubscriptionControllerMock extends SubscriptionController {
        }
        }
    }
    }
    @Override
    @Override
    public void clearDefaultsForInactiveSubIds() {
        throw new RuntimeException("not implemented");
    }
    @Override
    public void updatePhonesAvailability(Phone[] phones) {
    public void updatePhonesAvailability(Phone[] phones) {
        throw new RuntimeException("not implemented");
        throw new RuntimeException("not implemented");
    }
    }