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

Commit d622e14d authored by jackqdyulei's avatar jackqdyulei
Browse files

Refactor roaming preference

Use preferenceController instead

Bug: 114749736
Test: RunSettingsRoboTests
Change-Id: Idb0276ea0ed1738d93223e072338ba3c32498a9d
parent 51814935
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -36,7 +36,9 @@
        android:title="@string/roaming"
        android:persistent="false"
        android:summaryOn="@string/roaming_enable"
        android:summaryOff="@string/roaming_disable"/>
        android:summaryOff="@string/roaming_disable"
        settings:userRestriction="no_data_roaming"
        settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/>

    <Preference
        android:key="data_usage_summary"
+2 −79
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ import java.util.List;

@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkFragment extends DashboardFragment implements
        Preference.OnPreferenceChangeListener, RoamingDialogFragment.RoamingDialogListener {
        Preference.OnPreferenceChangeListener {

    // debug data
    private static final String LOG_TAG = "NetworkSettings";
@@ -153,7 +153,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
    //UI objects
    private ListPreference mButtonPreferredNetworkMode;
    private ListPreference mButtonEnabledNetworks;
    private RestrictedSwitchPreference mButtonDataRoam;
    private SwitchPreference mButton4glte;
    private Preference mLteDataServicePref;
    private Preference mEuiccSettingsPref;
@@ -228,15 +227,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
        return 0;
    }

    @Override
    public void onPositiveButtonClick(androidx.fragment.app.DialogFragment dialog) {
        mTelephonyManager.setDataRoamingEnabled(true);
        mButtonDataRoam.setChecked(true);
        MetricsLogger.action(getContext(),
                getMetricsEventCategory(getPreferenceScreen(), mButtonDataRoam),
                true);
    }

    /**
     * Invoked on each preference click in this hierarchy, overrides
     * PreferenceActivity's implementation.  Used to make sure we track the
@@ -299,9 +289,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
                    preferredNetworkMode);
            mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode));
            return true;
        } else if (preference == mButtonDataRoam) {
            // Do not disable the preference screen if the user clicks Data roaming.
            return true;
        } else if (preference == mEuiccSettingsPref) {
            Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);
            startActivity(intent);
@@ -398,6 +385,7 @@ public class MobileNetworkFragment extends DashboardFragment implements
                SubscriptionManager.INVALID_SUBSCRIPTION_ID);

        use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
        use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
        use(CdmaApnPreferenceController.class).init(mSubId);
        use(CarrierPreferenceController.class).init(mSubId);
        use(DataUsagePreferenceController.class).init(mSubId);
@@ -446,13 +434,10 @@ public class MobileNetworkFragment extends DashboardFragment implements
        //get UI object references
        PreferenceScreen prefSet = getPreferenceScreen();

        mButtonDataRoam = (RestrictedSwitchPreference) prefSet.findPreference(
                BUTTON_ROAMING_KEY);
        mButtonPreferredNetworkMode = (ListPreference) prefSet.findPreference(
                BUTTON_PREFERED_NETWORK_MODE);
        mButtonEnabledNetworks = (ListPreference) prefSet.findPreference(
                BUTTON_ENABLED_NETWORKS_KEY);
        mButtonDataRoam.setOnPreferenceChangeListener(this);

        mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY);

@@ -525,11 +510,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
        // preferences.
        getPreferenceScreen().setEnabled(true);

        // Set UI state in onResume because a user could go home, launch some
        // app to change this setting's backend, and re-launch this settings app
        // and the UI state would be inconsistent with actual state
        mButtonDataRoam.setChecked(mTelephonyManager.isDataRoamingEnabled());

        if (getPreferenceScreen().findPreference(BUTTON_PREFERED_NETWORK_MODE) != null
                || getPreferenceScreen().findPreference(BUTTON_ENABLED_NETWORKS_KEY) != null)  {
            updatePreferredNetworkUIFromDb();
@@ -579,25 +559,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
            // android.R.id.home will be triggered in onOptionsItemSelected()
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        prefSet.addPreference(mButtonDataRoam);

        mButtonDataRoam.setEnabled(hasActiveSubscriptions);

        if (hasActiveSubscriptions) {

            // Initialize states of mButtonDataRoam.
            mButtonDataRoam.setChecked(mTelephonyManager.isDataRoamingEnabled());
            if (mButtonDataRoam.isEnabled()) {
                if (RestrictedLockUtilsInternal.hasBaseUserRestriction(context,
                        UserManager.DISALLOW_DATA_ROAMING, UserHandle.myUserId())) {
                    mButtonDataRoam.setEnabled(false);
                } else {
                    mButtonDataRoam.checkRestrictionAndSetDisabled(
                            UserManager.DISALLOW_DATA_ROAMING);
                }
            }
        }
    }

    private void updateBody() {
@@ -1038,42 +999,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
            boolean enhanced4gMode = !mButton4glte.isChecked();
            mButton4glte.setChecked(enhanced4gMode);
            mImsMgr.setEnhanced4gLteModeSetting(mButton4glte.isChecked());
        } else if (preference == mButtonDataRoam) {
            if (DBG) log("onPreferenceTreeClick: preference == mButtonDataRoam.");

            //normally called on the toggle click
            if (!mButtonDataRoam.isChecked()) {
                PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
                        mSubId);
                if (carrierConfig != null && carrierConfig.getBoolean(
                        CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL)) {
                    mTelephonyManager.setDataRoamingEnabled(true);
                    MetricsLogger.action(getContext(),
                            getMetricsEventCategory(getPreferenceScreen(), mButtonDataRoam),
                            true);
                } else {
                    // MetricsEvent with no value update.
                    MetricsLogger.action(getContext(),
                            getMetricsEventCategory(getPreferenceScreen(), mButtonDataRoam));
                    // First confirm with a warning dialog about charges
                    mOkClicked = false;
                    RoamingDialogFragment
                            fragment = new RoamingDialogFragment();
                    Bundle b = new Bundle();
                    b.putInt(RoamingDialogFragment.SUB_ID_KEY, mSubId);
                    fragment.setArguments(b);
                    fragment.setTargetFragment(this, 0 /* requestCode */);
                    fragment.show(getFragmentManager(), ROAMING_TAG);
                    // Don't update the toggle unless the confirm button is actually pressed.
                    return false;
                }
            } else {
                mTelephonyManager.setDataRoamingEnabled(false);
                MetricsLogger.action(getContext(),
                        getMetricsEventCategory(getPreferenceScreen(), mButtonDataRoam),
                        false);
                return true;
            }
        } else if (preference == mVideoCallingPref) {
            // If mButton4glte is not checked, mVideoCallingPref should be disabled.
            // So it only makes sense to call phoneMgr.enableVideoCalling if it's checked.
@@ -1734,8 +1659,6 @@ public class MobileNetworkFragment extends DashboardFragment implements

        if (preference == null) {
            return MetricsProto.MetricsEvent.VIEW_UNKNOWN;
        } else if (preference == mButtonDataRoam) {
            return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE;
        } else if (preference == mLteDataServicePref) {
            return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE;
        } else if (preference == mButton4glte) {
+10 −18
Original line number Diff line number Diff line
@@ -23,11 +23,11 @@ import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;

import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;


import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;

@@ -42,15 +42,14 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
    private CarrierConfigManager mCarrierConfigManager;
    private int mSubId;

    /**
     * The interface we expect a host activity to implement.
     */
    public interface RoamingDialogListener {
        void onPositiveButtonClick(DialogFragment dialog);
    }
    public static RoamingDialogFragment newInstance(int subId) {
        final RoamingDialogFragment dialogFragment = new RoamingDialogFragment();
        Bundle args = new Bundle();
        args.putInt(SUB_ID_KEY, subId);
        dialogFragment.setArguments(args);

    // the host activity which implements the listening interface
    private RoamingDialogListener mListener;
        return dialogFragment;
    }

    @Override
    public void onAttach(Context context) {
@@ -58,14 +57,6 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
        Bundle args = getArguments();
        mSubId = args.getInt(SUB_ID_KEY);
        mCarrierConfigManager = new CarrierConfigManager(context);

        Fragment fragment = getTargetFragment();
        try {
            mListener = (RoamingDialogListener) fragment;
        } catch (ClassCastException e) {
            throw new ClassCastException(fragment.toString() +
                    "must implement RoamingDialogListener");
        }
    }

    @Override
@@ -95,7 +86,8 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
    public void onClick(DialogInterface dialog, int which) {
        // let the host know that the positive button has been clicked
        if (which == dialog.BUTTON_POSITIVE) {
            mListener.onPositiveButtonClick(this);
            TelephonyManager.from(getContext()).createForSubscriptionId(
                    mSubId).setDataRoamingEnabled(true);
        }
    }
}
+181 −0
Original line number 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.settings.network.telephony;

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.core.TogglePreferenceController;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;

/**
 * Preference controller for "Roaming"
 */
public class RoamingPreferenceController extends TogglePreferenceController implements
        LifecycleObserver, OnStart, OnStop {

    private static final String DIALOG_TAG = "MobileDataDialog";

    private RestrictedSwitchPreference mSwitchPreference;
    private TelephonyManager mTelephonyManager;
    private CarrierConfigManager mCarrierConfigManager;
    private int mSubId;
    private DataContentObserver mDataContentObserver;
    @VisibleForTesting
    boolean mNeedDialog;
    @VisibleForTesting
    FragmentManager mFragmentManager;

    public RoamingPreferenceController(Context context, String key) {
        super(context, key);
        mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
        mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper()));
    }

    @Override
    public void onStart() {
        mDataContentObserver.register(mContext, mSubId);
    }

    @Override
    public void onStop() {
        mDataContentObserver.unRegister(mContext);
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mSwitchPreference = (RestrictedSwitchPreference) screen.findPreference(getPreferenceKey());
    }

    @Override
    public int getAvailabilityStatus() {
        return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
                ? AVAILABLE
                : AVAILABLE_UNSEARCHABLE;
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            if (mNeedDialog) {
                showDialog();
            }
            return true;
        }

        return false;
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        mNeedDialog = isDialogNeeded();

        if (!mNeedDialog) {
            // Update data directly if we don't need dialog
            mTelephonyManager.setDataRoamingEnabled(isChecked);
            return true;
        }

        return false;
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        final RestrictedSwitchPreference switchPreference = (RestrictedSwitchPreference) preference;
        switchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        switchPreference.setChecked(isChecked());
    }

    @VisibleForTesting
    boolean isDialogNeeded() {
        final boolean isRoamingEnabled = mTelephonyManager.isDataRoamingEnabled();
        final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
                mSubId);

        // Need dialog if we need to turn on roaming and the roaming charge indication is allowed
        if (!isRoamingEnabled && (carrierConfig == null || !carrierConfig.getBoolean(
                CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL))) {
            return true;
        }
        return false;
    }

    @Override
    public boolean isChecked() {
        return mTelephonyManager.isDataRoamingEnabled();
    }

    public void init(FragmentManager fragmentManager, int subId) {
        mFragmentManager = fragmentManager;
        mSubId = subId;
        mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
    }

    private void showDialog() {
        final RoamingDialogFragment dialogFragment = RoamingDialogFragment.newInstance(mSubId);

        dialogFragment.show(mFragmentManager, DIALOG_TAG);
    }

    /**
     * Listener that listens data roaming change
     */
    public class DataContentObserver extends ContentObserver {

        public DataContentObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            updateState(mSwitchPreference);
        }

        public void register(Context context, int subId) {
            Uri uri = Settings.Global.getUriFor(Settings.Global.DATA_ROAMING);
            if (TelephonyManager.getDefault().getSimCount() != 1) {
                uri = Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + subId);
            }
            context.getContentResolver().registerContentObserver(uri, false, this);

        }

        public void unRegister(Context context) {
            context.getContentResolver().unregisterContentObserver(this);
        }
    }
}
+144 −0
Original line number 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.settings.network.telephony;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;

import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.RestrictedSwitchPreference;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;

@RunWith(SettingsRobolectricTestRunner.class)
public class RoamingPreferenceControllerTest {
    private static final int SUB_ID = 2;

    @Mock
    private FragmentManager mFragmentManager;
    @Mock
    private TelephonyManager mTelephonyManager;
    @Mock
    private TelephonyManager mInvalidTelephonyManager;
    @Mock
    private SubscriptionManager mSubscriptionManager;
    @Mock
    private FragmentTransaction mFragmentTransaction;
    @Mock
    private CarrierConfigManager mCarrierConfigManager;

    private RoamingPreferenceController mController;
    private RestrictedSwitchPreference mPreference;
    private Context mContext;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mContext = spy(RuntimeEnvironment.application);
        doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
        doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class);
        doReturn(mCarrierConfigManager).when(mContext).getSystemService(CarrierConfigManager.class);
        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
        doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
        doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();

        mPreference = new RestrictedSwitchPreference(mContext);
        mController = new RoamingPreferenceController(mContext, "roaming");
        mController.init(mFragmentManager, SUB_ID);
        mPreference.setKey(mController.getPreferenceKey());
    }

    @Test
    public void getAvailabilityStatus_validSubId_returnAvailable() {
        assertThat(mController.getAvailabilityStatus()).isEqualTo(
                BasePreferenceController.AVAILABLE);
    }

    @Test
    public void getAvailabilityStatus_invalidSubId_returnUnsearchable() {
        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID);

        assertThat(mController.getAvailabilityStatus()).isEqualTo(
                BasePreferenceController.AVAILABLE_UNSEARCHABLE);
    }

    @Test
    public void isDialogNeeded_roamingDisabledWithoutFlag_returnTrue() {
        final PersistableBundle bundle = new PersistableBundle();
        bundle.putBoolean(CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
        doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
        doReturn(false).when(mTelephonyManager).isDataRoamingEnabled();

        assertThat(mController.isDialogNeeded()).isTrue();
    }

    @Test
    public void isDialogNeeded_roamingEnabled_returnFalse() {
        doReturn(true).when(mTelephonyManager).isDataRoamingEnabled();

        assertThat(mController.isDialogNeeded()).isFalse();
    }

    @Test
    public void handlePreferenceTreeClick_needDialog_showDialog() {
        mController.mNeedDialog = true;

        mController.handlePreferenceTreeClick(mPreference);

        verify(mFragmentManager).beginTransaction();
    }

    @Test
    public void updateState_invalidSubId_disabled() {
        mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID);

        mController.updateState(mPreference);

        assertThat(mPreference.isEnabled()).isFalse();
    }

    @Test
    public void updateState_validSubId_enabled() {
        doReturn(true).when(mTelephonyManager).isDataRoamingEnabled();

        mController.updateState(mPreference);

        assertThat(mPreference.isEnabled()).isTrue();
        assertThat(mPreference.isChecked()).isTrue();
    }

}