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

Commit 8878c8de authored by Amit Mahajan's avatar Amit Mahajan Committed by Automerger Merge Worker
Browse files

Merge "Voice/Data/SMS preference auto selection" am: e20575b3

Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1425494

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: If0eea33688bf04ccf13d718e5d3e3d542505e267
parents 6a0becd2 e20575b3
Loading
Loading
Loading
Loading
+84 −1
Original line number Diff line number Diff line
@@ -148,6 +148,8 @@ public class MultiSimSettingController extends Handler {
    // device.
    private final boolean mIsAskEverytimeSupportedForSms;

    private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub";

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -309,6 +311,8 @@ public class MultiSimSettingController extends Handler {
        // If user is enabling a non-default non-opportunistic subscription, make it default.
        if (mSubController.getDefaultDataSubId() != subId && !mSubController.isOpportunistic(subId)
                && enable && mSubController.isActiveSubId(subId)) {
             android.provider.Settings.Global.putInt(mContext.getContentResolver(),
                 SETTING_USER_PREF_DATA_SUB, subId);
            mSubController.setDefaultDataSubId(subId);
        }
    }
@@ -572,7 +576,17 @@ public class MultiSimSettingController extends Handler {
                (newValue -> mSubController.setDefaultSmsSubId(newValue)),
                mIsAskEverytimeSupportedForSms);

        boolean autoFallbackEnabled = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_voice_data_sms_auto_fallback);

        // Based on config config_voice_data_sms_auto_fallback value choose voice/data/sms
        // preference auto selection logic or display notification for end used to
        // select voice/data/SMS preferences.
        if (!autoFallbackEnabled) {
            sendSubChangeNotificationIfNeeded(change, dataSelected, voiceSelected, smsSelected);
        } else {
            updateUserPreferences(mPrimarySubList, dataSelected, voiceSelected, smsSelected);
        }
    }

    @PrimarySubChangeType
@@ -888,6 +902,75 @@ public class MultiSimSettingController extends Handler {
        }
    }

    // Voice/Data/SMS preferences would be auto selected without any user
    // confirmation in following scenarios,
    // 1. When device powered-up with only one SIM Inserted or while two SIM cards
    // present if one SIM is removed(or turned OFF) the reaiming SIM would be
    // selected as preferred voice/data/sms SIM.
    // 2. When device powered-up with two SIM cards or if two SIM cards
    // present on device with new SIM insert(or SIM turn ON) the first inserted SIM
    // would be selected as preferred voice/data/sms SIM.
    private void updateUserPreferences(List<Integer> primarySubList, boolean dataSelected,
            boolean voiceSelected, boolean smsSelected) {
        // In Single SIM case or if there are no activated subs available, no need to update. EXIT.
        if ((primarySubList.isEmpty()) || (mSubController.getActiveSubInfoCountMax() == 1)) return;

        if (!isRadioAvailableOnAllSubs()) {
            log("Radio is in Invalid state, Ignore Updating User Preference!!!");
            return;
        }
        final int defaultDataSubId = mSubController.getDefaultDataSubId();

        if (DBG) log("updateUserPreferences:  dds = " + defaultDataSubId + " voice = "
                + mSubController.getDefaultVoiceSubId() +
                " sms = " + mSubController.getDefaultSmsSubId());

        int autoDefaultSubId = primarySubList.get(0);

        if ((primarySubList.size() == 1) && !smsSelected) {
            mSubController.setDefaultSmsSubId(autoDefaultSubId);
        }

        if ((primarySubList.size() == 1) && !voiceSelected) {
            mSubController.setDefaultVoiceSubId(autoDefaultSubId);
        }

        int userPrefDataSubId = getUserPrefDataSubIdFromDB();

        if (DBG) log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId
                 + " next active subId " + autoDefaultSubId);

        // If earlier user selected DDS is now available, set that as DDS subId.
        if (primarySubList.contains(userPrefDataSubId) &&
                SubscriptionManager.isValidSubscriptionId(userPrefDataSubId) &&
                (defaultDataSubId != userPrefDataSubId)) {
            mSubController.setDefaultDataSubId(userPrefDataSubId);
        } else if (!dataSelected) {
            mSubController.setDefaultDataSubId(autoDefaultSubId);
        }


        if (DBG) log("updateUserPreferences: after dds = " + mSubController.getDefaultDataSubId() +
                " voice = " + mSubController.getDefaultVoiceSubId() + " sms = " +
                 mSubController.getDefaultSmsSubId());
    }

    private int getUserPrefDataSubIdFromDB() {
        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                SETTING_USER_PREF_DATA_SUB, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    }

    private boolean isRadioAvailableOnAllSubs() {
        for (Phone phone : PhoneFactory.getPhones()) {
            if ((phone.mCi != null &&
                    phone.mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE) ||
                    phone.isShuttingDown()) {
                return false;
            }
        }
        return true;
    }

    private void log(String msg) {
        Log.d(LOG_TAG, msg);
    }
+0 −343
Original line number Diff line number Diff line
@@ -56,8 +56,6 @@ public class VendorSubscriptionController extends SubscriptionController {

    private static int sNumPhones;

    private static final int EVENT_UICC_APPS_ENABLEMENT_DONE = 101;

    private static final int PROVISIONED = 1;
    private static final int NOT_PROVISIONED = 0;

@@ -67,12 +65,6 @@ public class VendorSubscriptionController extends SubscriptionController {
    private RegistrantList mAddSubscriptionRecordRegistrants = new RegistrantList();

    private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub";
    /**
     * This intent would be broadcasted when a subId/slotId pair added to the
     * sSlotIdxToSubId hashmap.
     */
    private static final String ACTION_SUBSCRIPTION_RECORD_ADDED =
            "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED";

    public static VendorSubscriptionController init(Context c) {
        synchronized (VendorSubscriptionController.class) {
@@ -95,345 +87,10 @@ public class VendorSubscriptionController extends SubscriptionController {

    protected VendorSubscriptionController(Context c) {
        super(c);
        if (DBG) logd(" init by Context");

        mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        sNumPhones = TelephonyManager.getDefault().getPhoneCount();
    }

    public void registerForAddSubscriptionRecord(Handler handler, int what, Object obj) {
        Registrant r = new Registrant(handler, what, obj);
        synchronized (mAddSubscriptionRecordRegistrants) {
            mAddSubscriptionRecordRegistrants.add(r);
            List<SubscriptionInfo> subInfoList =
                    getActiveSubscriptionInfoList(mContext.getOpPackageName());
            if (subInfoList != null) {
                r.notifyRegistrant();
            }
        }
    }

    public void unregisterForAddSubscriptionRecord(Handler handler) {
        synchronized (mAddSubscriptionRecordRegistrants) {
            mAddSubscriptionRecordRegistrants.remove(handler);
        }
    }

    @Override
    public int addSubInfoRecord(String iccId, int slotIndex) {
        logd("addSubInfoRecord: broadcast intent subId[" + slotIndex + "]");
        return addSubInfo(iccId, null, slotIndex, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
    }

    @Override
    public int addSubInfo(String uniqueId, String displayName, int slotIndex,
            int subscriptionType) {

        int retVal = super.addSubInfo(uniqueId, displayName, slotIndex, subscriptionType);

        int[] subId = getSubId(slotIndex);
        if (subId != null && (subId.length > 0)) {
            // When a new entry added in sSlotIdxToSubId for slotId, broadcast intent
            logd("addSubInfoRecord: broadcast intent subId[" + slotIndex + "] = " + subId[0]);
            mAddSubscriptionRecordRegistrants.notifyRegistrants(
                    new AsyncResult(null, slotIndex, null));
            Intent intent = new Intent(ACTION_SUBSCRIPTION_RECORD_ADDED);
            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, slotIndex, subId[0]);
            mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
        }
        return retVal;
    }

    @Override
    public int setUiccApplicationsEnabled(boolean enabled, int subId) {
        if (DBG) logd("[setUiccApplicationsEnabled]+ enabled:" + enabled + " subId:" + subId);

        ContentValues value = new ContentValues(1);
        value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, enabled);

        int result = mContext.getContentResolver().update(
                SubscriptionManager.getUriForSubscriptionId(subId), value, null, null);

        // Refresh the Cache of Active Subscription Info List
        refreshCachedActiveSubscriptionInfoList();

        notifySubscriptionInfoChanged();

        if (isActiveSubId(subId)) {
            Phone phone = PhoneFactory.getPhone(getPhoneId(subId));
            phone.enableUiccApplications(enabled, Message.obtain(
                    mSubscriptionHandler, EVENT_UICC_APPS_ENABLEMENT_DONE, enabled));
        }

        return result;
    }

    /*
     * Handler Class
     */
    private Handler mSubscriptionHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_UICC_APPS_ENABLEMENT_DONE: {
                    logd("EVENT_UICC_APPS_ENABLEMENT_DONE");
                    AsyncResult ar = (AsyncResult) msg.obj;
                    if (ar.exception != null) {
                        logd("Received exception: " + ar.exception);
                        return;
                    }
                    updateUserPreferences();
                    break;
                }
            }
        }
    };

    protected boolean isRadioAvailableOnAllSubs() {
        for (int i = 0; i < sNumPhones; i++) {
            if (PhoneFactory.getPhone(i).mCi != null &&
                    PhoneFactory.getPhone(i).mCi.getRadioState() ==
                    TelephonyManager.RADIO_POWER_UNAVAILABLE) {
                return false;
            }
        }
        return true;
    }

    protected boolean isShuttingDown() {
        for (int i = 0; i < sNumPhones; i++) {
            if (PhoneFactory.getPhone(i) != null &&
                    PhoneFactory.getPhone(i).isShuttingDown()) return true;
        }
        return false;
    }

    public boolean isRadioInValidState() {

        // Radio Unavailable, do not updateUserPrefs. As this may happened due to SSR or RIL Crash.
        if (!isRadioAvailableOnAllSubs()) {
            logd(" isRadioInValidState, radio not available");
            return false;
        }

        //Do not updateUserPrefs when Shutdown is in progress
        if (isShuttingDown()) {
            logd(" isRadioInValidState: device shutdown in progress ");
            return false;
        }
        return true;
    }

    // If any of the voice/data/sms preference related SIM
    // deactivated/re-activated this will update the preference
    // with next available/activated SIM.
    public void updateUserPreferences() {
        SubscriptionInfo mNextActivatedSub = null;
        int activeCount = 0;
        if (!isRadioInValidState()) {
            logd("Radio is in Invalid state, Ignore Updating User Preference!!!");
            return;
        }
        List<SubscriptionInfo> sil = getActiveSubscriptionInfoList(mContext.getOpPackageName());
        // If list of active subscriptions empty OR non of the SIM provisioned
        // clear defaults preference of voice/sms/data.
        if (sil == null || sil.size() < 1) {
            logi("updateUserPreferences: Subscription list is empty");
            return;
        }

        // Do not fallback to next available sub if AOSP feature
        // "User choice of selecting data/sms fallback preference" enabled.
        if (SystemProperties.getBoolean("persist.vendor.radio.aosp_usr_pref_sel", false)) {
            logi("updateUserPreferences: AOSP user preference option enabled ");
            return;
        }

        final int defaultVoiceSubId = getDefaultVoiceSubId();
        final int defaultDataSubId = getDefaultDataSubId();
        final int defaultSmsSubId = getDefaultSmsSubId();

        //Get num of activated Subs and next available activated sub info.
        for (SubscriptionInfo subInfo : sil) {
            if (isUiccProvisioned(subInfo.getSimSlotIndex())) {
                activeCount++;
                if (mNextActivatedSub == null) mNextActivatedSub = subInfo;
            }
        }
        logd("updateUserPreferences:: active sub count = " + activeCount + " dds = "
                 + defaultDataSubId + " voice = " + defaultVoiceSubId +
                 " sms = " + defaultSmsSubId);

        // If active SUB count is 1, Always Ask Prompt to be disabled and
        // preference fallback to the next available SUB.
        if (activeCount == 1) {
            setSmsPromptEnabled(false);
        }

        // TODO Set all prompt options to false ?

        // in Single SIM case or if there are no activated subs available, no need to update. EXIT.
        if ((mNextActivatedSub == null) || (getActiveSubInfoCountMax() == 1)) return;

        handleDataPreference(mNextActivatedSub.getSubscriptionId());

        if ((defaultSmsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
                || activeCount == 1) && !isSubProvisioned(defaultSmsSubId)) {
            setDefaultSmsSubId(mNextActivatedSub.getSubscriptionId());
        }

        if ((defaultVoiceSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
                || activeCount == 1) && !isSubProvisioned(defaultVoiceSubId)) {
            setDefaultVoiceSubId(mNextActivatedSub.getSubscriptionId());
        }

        // voice preference is handled in such a way that
        // 1. Whenever current Sub is deactivated or removed It fall backs to
        //    next available Sub.
        // 2. When device is flashed for the first time, initial voice preference
        //    would be set to always ask.
        if (!isNonSimAccountFound() && activeCount == 1) {
            final int subId = mNextActivatedSub.getSubscriptionId();
            PhoneAccountHandle phoneAccountHandle = subscriptionIdToPhoneAccountHandle(subId);
            logi("set default phoneaccount to  " + subId);
            mTelecomManager.setUserSelectedOutgoingPhoneAccount(phoneAccountHandle);
        }
        if (!isSubProvisioned(sDefaultFallbackSubId.get())) {
            setDefaultFallbackSubId(mNextActivatedSub.getSubscriptionId(),
                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
        }

        notifySubscriptionInfoChanged();
        logd("updateUserPreferences: after currentDds = " + getDefaultDataSubId() + " voice = " +
                 getDefaultVoiceSubId() + " sms = " + getDefaultSmsSubId());
    }

    protected void handleDataPreference(int nextActiveSubId) {
        int userPrefDataSubId = getUserPrefDataSubIdFromDB();
        int currentDataSubId = getDefaultDataSubId();

        List<SubscriptionInfo> subInfoList =
                getActiveSubscriptionInfoList(mContext.getOpPackageName());
        if (subInfoList == null) {
            return;
        }
        boolean userPrefSubValid = false;
        for (SubscriptionInfo subInfo : subInfoList) {
            if (subInfo.getSubscriptionId() == userPrefDataSubId) {
                userPrefSubValid = true;
            }
        }
        logd("havePrefSub = " + userPrefSubValid + " user pref subId = "
                 + userPrefDataSubId + " current dds " + currentDataSubId
                 + " next active subId " + nextActiveSubId);

        // If earlier user selected DDS is now available, set that as DDS subId.
        if (userPrefSubValid && isSubProvisioned(userPrefDataSubId) &&
                 (currentDataSubId != userPrefDataSubId)) {
            setDefaultDataSubId(userPrefDataSubId);
        } else if (!isSubProvisioned(currentDataSubId)) {
            setDefaultDataSubId(nextActiveSubId);
        }

    }

    protected boolean isUiccProvisioned(int slotId) {
//        return isSubscriptionEnabled();
        return true;
    }

    // This method returns true if subId and corresponding slotId is in valid
    // range and the Uicc card corresponds to this slot is provisioned.
    protected boolean isSubProvisioned(int subId) {
        boolean isSubIdUsable = SubscriptionManager.isUsableSubIdValue(subId);

        if (isSubIdUsable) {
            int slotId = getSlotIndex(subId);
            if (!SubscriptionManager.isValidSlotIndex(slotId)) {
                loge(" Invalid slotId " + slotId + " or subId = " + subId);
                isSubIdUsable = false;
            } else {
                if (!isUiccProvisioned(slotId)) {
                    isSubIdUsable = false;
                }
                loge("isSubProvisioned, state = " + isSubIdUsable + " subId = " + subId);
            }
        }
        return isSubIdUsable;
    }

    /* Returns User SMS Prompt property,  enabled or not */
    public boolean isSmsPromptEnabled() {
        boolean prompt = false;
        int value = 0;
        try {
            value = Settings.Global.getInt(mContext.getContentResolver(),
                    Settings.Global.MULTI_SIM_SMS_PROMPT);
        } catch (SettingNotFoundException snfe) {
            loge("Settings Exception Reading Dual Sim SMS Prompt Values");
        }
        prompt = (value == 0) ? false : true ;
        if (VDBG) logd("SMS Prompt option:" + prompt);

       return prompt;
    }

    /*Sets User SMS Prompt property,  enable or not */
    public void setSmsPromptEnabled(boolean enabled) {
        enforceModifyPhoneState("setSMSPromptEnabled");
        int value = (enabled == false) ? 0 : 1;
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.MULTI_SIM_SMS_PROMPT, value);
        logi("setSMSPromptOption to " + enabled);
    }

    protected boolean isNonSimAccountFound() {
        final Iterator<PhoneAccountHandle> phoneAccounts =
                mTelecomManager.getCallCapablePhoneAccounts().listIterator();

        while (phoneAccounts.hasNext()) {
            final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next();
            final PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(phoneAccountHandle);
            if (mTelephonyManager.getSubIdForPhoneAccount(phoneAccount) ==
                            SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                logi("Other than SIM account found. ");
                return true;
            }
        }
        logi("Other than SIM account not found ");
        return false;
    }

    protected PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) {
        final Iterator<PhoneAccountHandle> phoneAccounts =
                mTelecomManager.getCallCapablePhoneAccounts().listIterator();

        while (phoneAccounts.hasNext()) {
            final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next();
            final PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(phoneAccountHandle);
            if (subId == mTelephonyManager.getSubIdForPhoneAccount(phoneAccount)) {
                return phoneAccountHandle;
            }
        }

        return null;
    }

    protected int getUserPrefDataSubIdFromDB() {
        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                SETTING_USER_PREF_DATA_SUB, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
    }

    private void logd(String string) {
        if (DBG) Rlog.d(LOG_TAG, string);
    }

    private void logi(String string) {
        Rlog.i(LOG_TAG, string);
    }

    private void loge(String string) {
        Rlog.e(LOG_TAG, string);
    }
}
+33 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.content.Intent;
import android.content.res.Resources;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -49,6 +50,7 @@ import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.InstrumentationRegistry;

import com.android.internal.telephony.dataconnection.DataEnabledSettings;

@@ -84,6 +86,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
    @Mock
    private DataEnabledSettings mDataEnabledSettingsMock2;
    private Phone[] mPhones;
    @Mock
    private CommandsInterface mMockCi;

    ParcelUuid mGroupUuid1 = new ParcelUuid(UUID.randomUUID());

@@ -750,4 +754,33 @@ public class MultiSimSettingControllerTest extends TelephonyTest {
            Assert.fail("InterruptedException during latch.await");
        }
    }

    @Test
    @SmallTest
    public void testVoiceDataSmsAutoFallback() throws Exception {
        doReturn(1).when(mSubControllerMock).getDefaultDataSubId();
        mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
        mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0,1);
        mMultiSimSettingControllerUT.notifyCarrierConfigChanged(2, 3);
        processAllMessages();
        verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt());
        verify(mSubControllerMock, never()).getActiveSubInfoCountMax();
        doReturn(2).when(mSubControllerMock).getActiveSubInfoCountMax();
        mPhoneMock1.mCi = mMockCi;
        mPhoneMock2.mCi = mMockCi;
        doReturn(TelephonyManager.RADIO_POWER_ON).when(mMockCi).getRadioState();
        doReturn(false).when(mPhoneMock1).isShuttingDown();
        doReturn(false).when(mPhoneMock2).isShuttingDown();
        android.provider.Settings.Global.putInt(InstrumentationRegistry.getTargetContext().
                 getContentResolver(), "user_preferred_data_sub", 2);
        Resources resources = mContext.getResources();
        doReturn(true).when(resources).getBoolean(
                com.android.internal.R.bool.config_voice_data_sms_auto_fallback);
        mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
        mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0,1);
        mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2);
        processAllMessages();
        verify(mSubControllerMock).getActiveSubInfoCountMax();
        verify(mSubControllerMock).setDefaultDataSubId(anyInt());
    }
}