diff --git a/res/xml/network_setting_fragment.xml b/res/xml/network_setting_fragment.xml index c383ab6652b..396f2e4a6c6 100644 --- a/res/xml/network_setting_fragment.xml +++ b/res/xml/network_setting_fragment.xml @@ -16,6 +16,8 @@ - + android:summary="@string/mobile_data_settings_summary" + settings:controller="com.android.settings.mobilenetwork.MobileDataPreferenceController"/> 1); - final boolean isMultipleDataOnCapable = - (mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1); - final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null - && currentSir.getSubscriptionId() == nextSir.getSubscriptionId()); - if (mChecked) { - if (!isMultiSim) { - // disabling data; show confirmation dialog which eventually - // calls setMobileDataEnabled() once user confirms. - mMultiSimDialog = false; - super.performClick(); - } else { - // Don't show any dialog. - setMobileDataEnabled(false /* enabled */, false /* disableOtherSubscriptions */); - } - } else { - if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) { - // enabling data and setting to default; show confirmation dialog which eventually - // calls setMobileDataEnabled() once user confirms. - mMultiSimDialog = true; - super.performClick(); - } else { - // Don't show any dialog. - setMobileDataEnabled(true /* enabled */, false /* disableOtherSubscriptions */); - } - } - } - - private void setMobileDataEnabled(boolean enabled, boolean disableOtherSubscriptions) { - if (DBG) Log.d(TAG, "setMobileDataEnabled(" + enabled + "," + mSubId + ")"); - - MetricsLogger.action(getContext(), MetricsEvent.ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE, - enabled); - - mTelephonyManager.setDataEnabled(mSubId, enabled); - - if (disableOtherSubscriptions) { - disableDataForOtherSubscriptions(mSubId); - } - - setChecked(enabled); - } - - private void setChecked(boolean checked) { - if (mChecked == checked) return; - mChecked = checked; - notifyChanged(); - } - - @Override - public void onBindViewHolder(PreferenceViewHolder holder) { - super.onBindViewHolder(holder); - View checkableView = holder.findViewById(com.android.internal.R.id.switch_widget); - checkableView.setClickable(false); - ((Checkable) checkableView).setChecked(mChecked); - } - - //TODO(b/114749736): move it to preference controller - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { - if (mMultiSimDialog) { - showMultiSimDialog(builder); - } else { - showDisableDialog(builder); - } - } - - private void showDisableDialog(AlertDialog.Builder builder) { - builder.setTitle(null) - .setMessage(R.string.data_usage_disable_mobile) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, null); - } - - private void showMultiSimDialog(AlertDialog.Builder builder) { - final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(mSubId); - final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); - - final String previousName = (nextSir == null) - ? getContext().getResources().getString(R.string.sim_selection_required_pref) - : nextSir.getDisplayName().toString(); - - builder.setTitle(R.string.sim_change_data_title); - builder.setMessage(getContext().getString(R.string.sim_change_data_message, - String.valueOf(currentSir != null ? currentSir.getDisplayName() : null), - previousName)); - - builder.setPositiveButton(android.R.string.ok, this); - builder.setNegativeButton(R.string.cancel, null); - } - - private void disableDataForOtherSubscriptions(int subId) { - List subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); - if (subInfoList != null) { - for (SubscriptionInfo subInfo : subInfoList) { - if (subInfo.getSubscriptionId() != subId) { - mTelephonyManager.setDataEnabled(subInfo.getSubscriptionId(), false); - } - } - } - } - - @Override - public void onClick(DialogInterface dialog, int which) { - if (which != DialogInterface.BUTTON_POSITIVE) { - return; - } - if (mMultiSimDialog) { - mSubscriptionManager.setDefaultDataSubId(mSubId); - setMobileDataEnabled(true /* enabled */, true /* disableOtherSubscriptions */); - } else { - // TODO: extend to modify policy enabled flag. - setMobileDataEnabled(false /* enabled */, false /* disableOtherSubscriptions */); - } - } - - private final DataStateListener mListener = new DataStateListener() { - @Override - public void onChange(boolean selfChange) { - updateChecked(); - } - }; - - /** - * Listener that listens mobile data state change. - */ - public abstract static class DataStateListener extends ContentObserver { - public DataStateListener() { - super(new Handler(Looper.getMainLooper())); - } - - /** - * Set / Unset data state listening, specifying subId. - */ - public void setListener(boolean listening, int subId, Context context) { - if (listening) { - Uri uri = Global.getUriFor(Global.MOBILE_DATA); - if (TelephonyManager.getDefault().getSimCount() != 1) { - uri = Global.getUriFor(Global.MOBILE_DATA + subId); - } - context.getContentResolver().registerContentObserver(uri, false, this); - } else { - context.getContentResolver().unregisterContentObserver(this); - } - } - } - - /** - * Class that represents state of mobile data state. - * Used by onSaveInstanceState and onRestoreInstanceState. - */ - public static class CellDataState extends BaseSavedState { - public int mSubId; - public boolean mChecked; - public boolean mMultiSimDialog; - - public CellDataState(Parcelable base) { - super(base); - } - - public CellDataState(Parcel source) { - super(source); - mChecked = source.readByte() != 0; - mMultiSimDialog = source.readByte() != 0; - mSubId = source.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeByte((byte) (mChecked ? 1 : 0)); - dest.writeByte((byte) (mMultiSimDialog ? 1 : 0)); - dest.writeInt(mSubId); - } - - public static final Creator CREATOR = new Creator() { - @Override - public CellDataState createFromParcel(Parcel source) { - return new CellDataState(source); - } - - @Override - public CellDataState[] newArray(int size) { - return new CellDataState[size]; - } - }; - } -} diff --git a/src/com/android/settings/mobilenetwork/MobileDataPreferenceController.java b/src/com/android/settings/mobilenetwork/MobileDataPreferenceController.java new file mode 100644 index 00000000000..c341d7e0095 --- /dev/null +++ b/src/com/android/settings/mobilenetwork/MobileDataPreferenceController.java @@ -0,0 +1,189 @@ +/* + * 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.mobilenetwork; + +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.telephony.SubscriptionInfo; +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 androidx.preference.SwitchPreference; + +import com.android.settings.core.TogglePreferenceController; +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 "Mobile data" + */ +public class MobileDataPreferenceController extends TogglePreferenceController + implements LifecycleObserver, OnStart, OnStop { + + private static final String DIALOG_TAG = "MobileDataDialog"; + + private SwitchPreference mPreference; + private TelephonyManager mTelephonyManager; + private SubscriptionManager mSubscriptionManager; + private DataContentObserver mDataContentObserver; + private FragmentManager mFragmentManager; + private int mSubId; + @VisibleForTesting + int mDialogType; + @VisibleForTesting + boolean mNeedDialog; + + public MobileDataPreferenceController(Context context, String key) { + super(context, key); + mSubscriptionManager = context.getSystemService(SubscriptionManager.class); + mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); + } + + @Override + public int getAvailabilityStatus() { + return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey()); + } + + @Override + public void onStart() { + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mDataContentObserver.register(mContext, mSubId); + } + } + + @Override + public void onStop() { + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mDataContentObserver.unRegister(mContext); + } + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { + if (mNeedDialog) { + showDialog(mDialogType); + } + return true; + } + + return false; + } + + @Override + public boolean setChecked(boolean isChecked) { + mNeedDialog = isDialogNeeded(); + + if (!mNeedDialog) { + // Update data directly if we don't need dialog + MobileNetworkUtils.setMobileDataEnabled(mContext, mSubId, isChecked, false); + return true; + } + + return false; + } + + @Override + public boolean isChecked() { + return mTelephonyManager.isDataEnabled(); + } + + public void init(FragmentManager fragmentManager, int subId) { + mFragmentManager = fragmentManager; + mSubId = subId; + mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); + } + + @VisibleForTesting + boolean isDialogNeeded() { + final boolean enableData = !mTelephonyManager.isDataEnabled(); + final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo( + mSubId); + final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo(); + final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1); + final boolean isMultipleDataOnCapable = + (mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1); + final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null + && currentSir.getSubscriptionId() == nextSir.getSubscriptionId()); + if (enableData) { + if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) { + mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG; + return true; + } + } else { + if (!isMultiSim) { + mDialogType = MobileDataDialogFragment.TYPE_DISABLE_DIALOG; + return true; + } + } + + return false; + } + + private void showDialog(int type) { + final MobileDataDialogFragment dialogFragment = MobileDataDialogFragment.newInstance(type, + mSubId); + dialogFragment.show(mFragmentManager, DIALOG_TAG); + } + + /** + * Listener that listens mobile data state change. + */ + public class DataContentObserver extends ContentObserver { + + public DataContentObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + updateState(mPreference); + } + + public void register(Context context, int subId) { + Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + if (TelephonyManager.getDefault().getSimCount() != 1) { + uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId); + } + context.getContentResolver().registerContentObserver(uri, false, this); + + } + + public void unRegister(Context context) { + context.getContentResolver().unregisterContentObserver(this); + } + } +} diff --git a/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java b/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java index d8df8fac555..b31d4d2dfd0 100644 --- a/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java +++ b/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java @@ -34,6 +34,7 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.UserHandle; import android.os.UserManager; +import android.provider.SearchIndexableResource; import android.provider.Settings; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; @@ -61,8 +62,11 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedSwitchPreference; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -156,7 +160,6 @@ public class MobileNetworkFragment extends DashboardFragment implements private Preference mWiFiCallingPref; private SwitchPreference mVideoCallingPref; private NetworkSelectListPreference mButtonNetworkSelect; - private MobileDataPreference mMobileDataPref; private DataUsagePreference mDataUsagePref; private static final String iface = "rmnet0"; //TODO: this will go away @@ -238,6 +241,9 @@ public class MobileNetworkFragment extends DashboardFragment implements */ @Override public boolean onPreferenceTreeClick(Preference preference) { + if (super.onPreferenceTreeClick(preference)) { + return true; + } sendMetricsEventPreferenceClicked(getPreferenceScreen(), preference); /** TODO: Refactor and get rid of the if's using subclasses */ @@ -298,7 +304,7 @@ public class MobileNetworkFragment extends DashboardFragment implements startActivity(intent); return true; } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref - || preference == mMobileDataPref || preference == mDataUsagePref) { + || preference == mDataUsagePref) { return false; } else { // if the button is anything but the simple toggle preference, @@ -383,6 +389,15 @@ public class MobileNetworkFragment extends DashboardFragment implements mPhoneStateListener.updateSubscriptionId(mSubId); } + @Override + public void onAttach(Context context) { + super.onAttach(context); + mSubId = getArguments().getInt(MobileSettingsActivity.KEY_SUBSCRIPTION_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + + use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId); + } + @Override public void onCreate(Bundle icicle) { Log.i(LOG_TAG, "onCreate:+"); @@ -407,7 +422,6 @@ public class MobileNetworkFragment extends DashboardFragment implements mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY); mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY); mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY); - mMobileDataPref = (MobileDataPreference) findPreference(BUTTON_MOBILE_DATA_ENABLE_KEY); mDataUsagePref = (DataUsagePreference) findPreference(BUTTON_DATA_USAGE_KEY); try { @@ -439,8 +453,6 @@ public class MobileNetworkFragment extends DashboardFragment implements // Initialize mActiveSubInfo int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); mActiveSubInfos = mSubscriptionManager.getActiveSubscriptionInfoList(); - mSubId = getArguments().getInt(MobileSettingsActivity.KEY_SUBSCRIPTION_ID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); updatePhone(); if (hasActiveSubscriptions()) { @@ -490,14 +502,6 @@ public class MobileNetworkFragment extends DashboardFragment implements } } - @Override - public void onDestroy() { - super.onDestroy(); - if (mMobileDataPref != null) { - mMobileDataPref.dispose(); - } - } - @Override public void onResume() { super.onResume(); @@ -567,17 +571,14 @@ public class MobileNetworkFragment extends DashboardFragment implements actionBar.setDisplayHomeAsUpEnabled(true); } - prefSet.addPreference(mMobileDataPref); prefSet.addPreference(mButtonDataRoam); prefSet.addPreference(mDataUsagePref); - mMobileDataPref.setEnabled(hasActiveSubscriptions); mButtonDataRoam.setEnabled(hasActiveSubscriptions); mDataUsagePref.setEnabled(hasActiveSubscriptions); if (hasActiveSubscriptions) { // Customized preferences needs to be initialized with subId. - mMobileDataPref.initialize(phoneSubId); mDataUsagePref.initialize(phoneSubId); // Initialize states of mButtonDataRoam. @@ -609,8 +610,6 @@ public class MobileNetworkFragment extends DashboardFragment implements return; } - prefSet.removeAll(); - updateBodyBasicFields(activity, prefSet, mSubId, hasActiveSubscriptions); if (hasActiveSubscriptions) { @@ -1751,8 +1750,6 @@ public class MobileNetworkFragment extends DashboardFragment implements if (preference == null) { return MetricsProto.MetricsEvent.VIEW_UNKNOWN; - } else if (preference == mMobileDataPref) { - return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE; } else if (preference == mButtonDataRoam) { return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE; } else if (preference == mDataUsagePref) { @@ -1864,6 +1861,17 @@ public class MobileNetworkFragment extends DashboardFragment implements protected boolean isPageSearchEnabled(Context context) { return false; } + + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.network_setting_fragment; + result.add(sir); + return result; + } }; private static final class SetPreferredNetworkAsyncTask extends AsyncTask { diff --git a/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java b/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java index 21093758a3f..44b1cef8b61 100644 --- a/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java +++ b/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java @@ -22,13 +22,14 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.database.Cursor; import android.os.PersistableBundle; import android.os.SystemProperties; import android.provider.Settings; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; import android.telephony.ims.feature.ImsFeature; @@ -170,4 +171,30 @@ public class MobileNetworkUtils { //TODO(b/114749736): get carrier config from subId return new PersistableBundle(); } + + /** + * Set whether to enable data for {@code subId}, also whether to disable data for other + * subscription + */ + public static void setMobileDataEnabled(Context context, int subId, boolean enabled, + boolean disableOtherSubscriptions) { + final TelephonyManager telephonyManager = TelephonyManager.from(context) + .createForSubscriptionId(subId); + final SubscriptionManager subscriptionManager = context.getSystemService( + SubscriptionManager.class); + telephonyManager.setDataEnabled(enabled); + + if (disableOtherSubscriptions) { + List subInfoList = + subscriptionManager.getActiveSubscriptionInfoList(); + if (subInfoList != null) { + for (SubscriptionInfo subInfo : subInfoList) { + if (subInfo.getSubscriptionId() != subId) { + TelephonyManager.from(context).createForSubscriptionId( + subInfo.getSubscriptionId()).setDataEnabled(false); + } + } + } + } + } } \ No newline at end of file diff --git a/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java b/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java index 37a180cf3e8..ba92ebf7955 100644 --- a/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java +++ b/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java @@ -23,6 +23,11 @@ import android.telephony.SubscriptionManager; import android.view.Menu; import android.view.View; +import androidx.annotation.VisibleForTesting; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + import com.android.internal.util.CollectionUtils; import com.android.settings.R; import com.android.settings.core.SettingsBaseActivity; @@ -31,11 +36,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import java.util.List; -import androidx.annotation.VisibleForTesting; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - public class MobileSettingsActivity extends SettingsBaseActivity { @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/mobilenetwork/MobileDataPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/mobilenetwork/MobileDataPreferenceControllerTest.java new file mode 100644 index 00000000000..9bf9b545153 --- /dev/null +++ b/tests/robotests/src/com/android/settings/mobilenetwork/MobileDataPreferenceControllerTest.java @@ -0,0 +1,149 @@ +/* + * 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.mobilenetwork; + +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.preference.SwitchPreference; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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 MobileDataPreferenceControllerTest { + 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 SubscriptionInfo mSubscriptionInfo; + @Mock + private FragmentTransaction mFragmentTransaction; + + private MobileDataPreferenceController mController; + private SwitchPreference 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(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID); + doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction(); + + mPreference = new SwitchPreference(mContext); + mController = new MobileDataPreferenceController(mContext, "mobile_data"); + mController.init(mFragmentManager, SUB_ID); + mPreference.setKey(mController.getPreferenceKey()); + } + + @Test + public void getAvailabilityStatus_invalidSubscription_returnUnavailable() { + mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void isDialogNeeded_disableSingleSim_returnTrue() { + doReturn(true).when(mTelephonyManager).isDataEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + doReturn(1).when(mTelephonyManager).getSimCount(); + + assertThat(mController.isDialogNeeded()).isTrue(); + assertThat(mController.mDialogType).isEqualTo(MobileDataDialogFragment.TYPE_DISABLE_DIALOG); + } + + @Test + public void isDialogNeeded_enableNonDefaultSimInMultiSimMode_returnTrue() { + doReturn(false).when(mTelephonyManager).isDataEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + doReturn(null).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + doReturn(2).when(mTelephonyManager).getSimCount(); + doReturn(1).when(mTelephonyManager).getNumberOfModemsWithSimultaneousDataConnections(); + + assertThat(mController.isDialogNeeded()).isTrue(); + assertThat(mController.mDialogType).isEqualTo( + MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG); + } + + @Test + public void handlePreferenceTreeClick_needDialog_showDialog() { + mController.mNeedDialog = true; + + mController.handlePreferenceTreeClick(mPreference); + + verify(mFragmentManager).beginTransaction(); + } + + @Test + public void onPreferenceChange_needDialog_doNothing() { + doReturn(true).when(mTelephonyManager).isDataEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + doReturn(1).when(mTelephonyManager).getSimCount(); + + mController.onPreferenceChange(mPreference, true); + + verify(mTelephonyManager, never()).setDataEnabled(true); + } + + @Test + public void onPreferenceChange_notNeedDialog_update() { + doReturn(true).when(mTelephonyManager).isDataEnabled(); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + doReturn(2).when(mTelephonyManager).getSimCount(); + + mController.onPreferenceChange(mPreference, true); + + verify(mTelephonyManager).setDataEnabled(true); + } + +} diff --git a/tests/robotests/src/com/android/settings/mobilenetwork/MobileNetworkUtilsTest.java b/tests/robotests/src/com/android/settings/mobilenetwork/MobileNetworkUtilsTest.java new file mode 100644 index 00000000000..2b21f1fac5c --- /dev/null +++ b/tests/robotests/src/com/android/settings/mobilenetwork/MobileNetworkUtilsTest.java @@ -0,0 +1,99 @@ +/* + * 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.mobilenetwork; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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; + +import java.util.Arrays; + +@RunWith(SettingsRobolectricTestRunner.class) +public class MobileNetworkUtilsTest { + private static final int SUB_ID_1 = 1; + private static final int SUB_ID_2 = 2; + + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private TelephonyManager mTelephonyManager2; + @Mock + private SubscriptionManager mSubscriptionManager; + @Mock + private SubscriptionInfo mSubscriptionInfo1; + @Mock + private SubscriptionInfo mSubscriptionInfo2; + + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class); + doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID_1); + doReturn(mTelephonyManager2).when(mTelephonyManager).createForSubscriptionId(SUB_ID_2); + + doReturn(SUB_ID_1).when(mSubscriptionInfo1).getSubscriptionId(); + doReturn(SUB_ID_2).when(mSubscriptionInfo2).getSubscriptionId(); + + doReturn(Arrays.asList(mSubscriptionInfo1, mSubscriptionInfo2)).when( + mSubscriptionManager).getActiveSubscriptionInfoList(); + } + + @Test + public void setMobileDataEnabled_setEnabled_enabled() { + MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_1, true, false); + + verify(mTelephonyManager).setDataEnabled(true); + verify(mTelephonyManager2, never()).setDataEnabled(anyBoolean()); + } + + @Test + public void setMobileDataEnabled_setDisabled_disabled() { + MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_2, true, false); + + verify(mTelephonyManager2).setDataEnabled(true); + verify(mTelephonyManager, never()).setDataEnabled(anyBoolean()); + } + + @Test + public void setMobileDataEnabled_disableOtherSubscriptions() { + MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_1, true, true); + + verify(mTelephonyManager).setDataEnabled(true); + verify(mTelephonyManager2).setDataEnabled(false); + } +} diff --git a/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java b/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java index cb86d6f3d27..a5a26b47e72 100644 --- a/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java +++ b/tests/robotests/src/com/android/settings/mobilenetwork/MobileSettingsActivityTest.java @@ -30,6 +30,10 @@ import android.telephony.SubscriptionManager; import android.view.Menu; import android.view.View; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + import com.android.internal.view.menu.ContextMenuBuilder; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -46,10 +50,6 @@ import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.List; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; - @RunWith(SettingsRobolectricTestRunner.class) public class MobileSettingsActivityTest {