diff --git a/res/values/strings.xml b/res/values/strings.xml index d5b0ae6df61..e160f8ecf3e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6994,6 +6994,10 @@ Preferred network type LTE (recommended) + + MMS messages + + Send & receive when mobile data is off Work SIM diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml index e7cc1dcd987..6682437bc74 100644 --- a/res/xml/mobile_network_settings_v2.xml +++ b/res/xml/mobile_network_settings_v2.xml @@ -73,6 +73,12 @@ android:title="@string/billing_cycle" settings:controller="com.android.settings.datausage.BillingCyclePreferenceController" /> + + updateState(mPreference)); + } + + @Override + public int getAvailabilityStatus(int subId) { + final TelephonyManager telephonyManager = TelephonyManager + .from(mContext).createForSubscriptionId(subId); + return (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + && !telephonyManager.isDataEnabled() + && telephonyManager.isApnMetered(ApnSetting.TYPE_MMS)) + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void onStart() { + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mMobileDataContentObserver.register(mContext, mSubId); + } + } + + @Override + public void onStop() { + if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mMobileDataContentObserver.unRegister(mContext); + } + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + preference.setVisible(isAvailable()); + ((SwitchPreference) preference).setChecked(isChecked()); + } + + public void init(int subId) { + mSubId = subId; + mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); + } + + @Override + public boolean setChecked(boolean isChecked) { + return mSubscriptionManager.setAlwaysAllowMmsData(mSubId, isChecked); + } + + @Override + public boolean isChecked() { + return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS); + } +} diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java index de54879abc2..a0e50fcbd80 100644 --- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java +++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java @@ -27,6 +27,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import com.android.settings.network.MobileDataContentObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; @@ -48,7 +49,7 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon private SwitchPreference mPreference; private TelephonyManager mTelephonyManager; private SubscriptionManager mSubscriptionManager; - private DataContentObserver mDataContentObserver; + private MobileDataContentObserver mDataContentObserver; private FragmentManager mFragmentManager; @VisibleForTesting int mDialogType; @@ -58,7 +59,8 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon public MobileDataPreferenceController(Context context, String key) { super(context, key); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); - mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper())); + mDataContentObserver = new MobileDataContentObserver(new Handler(Looper.getMainLooper())); + mDataContentObserver.setOnMobileDataChangedListener(()-> updateState(mPreference)); } @Override @@ -129,14 +131,6 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon return info != null && info.isOpportunistic(); } - public static Uri getObservableUri(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); - } - return uri; - } - public void init(FragmentManager fragmentManager, int subId) { mFragmentManager = fragmentManager; mSubId = subId; @@ -170,30 +164,4 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon 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) { - final Uri uri = getObservableUri(subId); - context.getContentResolver().registerContentObserver(uri, false, this); - - } - - public void unRegister(Context context) { - context.getContentResolver().unregisterContentObserver(this); - } - } } diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java index 28cb11e248e..bf9fc044617 100644 --- a/src/com/android/settings/network/telephony/MobileDataSlice.java +++ b/src/com/android/settings/network/telephony/MobileDataSlice.java @@ -39,6 +39,7 @@ import androidx.slice.builders.SliceAction; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.network.AirplaneModePreferenceController; +import com.android.settings.network.MobileDataContentObserver; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; import com.android.settings.slices.SliceBackgroundWorker; @@ -267,7 +268,7 @@ public class MobileDataSlice implements CustomSliceable { } public void register(Context context, int subId) { - final Uri uri = MobileDataPreferenceController.getObservableUri(subId); + final Uri uri = MobileDataContentObserver.getObservableUri(subId); context.getContentResolver().registerContentObserver(uri, false, this); } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index 35787927481..db99258a57b 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -136,6 +136,7 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId); use(CarrierSettingsVersionPreferenceController.class).init(mSubId); use(BillingCyclePreferenceController.class).init(mSubId); + use(MmsMessagePreferenceController.class).init(mSubId); } use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId); use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId); diff --git a/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java new file mode 100644 index 00000000000..0263fe9fdcd --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2019 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.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; + +import androidx.preference.SwitchPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSubscriptionManager; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowSubscriptionManager.class) +public class MmsMessagePreferenceControllerTest { + private static final int SUB_ID = 2; + + @Mock + private TelephonyManager mTelephonyManager; + @Mock + private SubscriptionManager mSubscriptionManager; + + private MmsMessagePreferenceController mController; + private SwitchPreference mPreference; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); + when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); + + mPreference = new SwitchPreference(mContext); + mController = new MmsMessagePreferenceController(mContext, "mms_message"); + ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID); + mController.init(SUB_ID); + mPreference.setKey(mController.getPreferenceKey()); + } + + @Test + public void getAvailabilityStatus_invalidSubscription_returnUnavailable() { + mController.init(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_mobileDataOn_returnUnavailable() { + when(mTelephonyManager.isDataEnabled()).thenReturn(true); + + assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_meteredOff_returnUnavailable() { + when(mTelephonyManager.isApnMetered(ApnSetting.TYPE_MMS)).thenReturn(false); + + assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_mobileDataOffWithValidSubId_returnAvailable() { + mController.init(SUB_ID); + when(mTelephonyManager.isDataEnabled()).thenReturn(false); + when(mTelephonyManager.isApnMetered(ApnSetting.TYPE_MMS)).thenReturn(true); + + assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(AVAILABLE); + } + + @Test + public void isChecked_returnDataFromTelephonyManager() { + when(mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS)).thenReturn(false); + assertThat(mController.isChecked()).isFalse(); + + when(mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS)).thenReturn(true); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void setChecked_setDataIntoSubscriptionManager() { + mController.setChecked(true); + verify(mSubscriptionManager).setAlwaysAllowMmsData(SUB_ID, true); + + mController.setChecked(false); + verify(mSubscriptionManager).setAlwaysAllowMmsData(SUB_ID, false); + } +}