Refactor roaming preference

Use preferenceController instead

Bug: 114749736
Test: RunSettingsRoboTests
Change-Id: Idb0276ea0ed1738d93223e072338ba3c32498a9d
This commit is contained in:
jackqdyulei
2018-10-15 17:31:16 -07:00
parent 5181493586
commit d622e14d85
5 changed files with 340 additions and 98 deletions

View File

@@ -36,7 +36,9 @@
android:title="@string/roaming" android:title="@string/roaming"
android:persistent="false" android:persistent="false"
android:summaryOn="@string/roaming_enable" 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 <Preference
android:key="data_usage_summary" android:key="data_usage_summary"

View File

@@ -81,7 +81,7 @@ import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkFragment extends DashboardFragment implements public class MobileNetworkFragment extends DashboardFragment implements
Preference.OnPreferenceChangeListener, RoamingDialogFragment.RoamingDialogListener { Preference.OnPreferenceChangeListener {
// debug data // debug data
private static final String LOG_TAG = "NetworkSettings"; private static final String LOG_TAG = "NetworkSettings";
@@ -153,7 +153,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
//UI objects //UI objects
private ListPreference mButtonPreferredNetworkMode; private ListPreference mButtonPreferredNetworkMode;
private ListPreference mButtonEnabledNetworks; private ListPreference mButtonEnabledNetworks;
private RestrictedSwitchPreference mButtonDataRoam;
private SwitchPreference mButton4glte; private SwitchPreference mButton4glte;
private Preference mLteDataServicePref; private Preference mLteDataServicePref;
private Preference mEuiccSettingsPref; private Preference mEuiccSettingsPref;
@@ -228,15 +227,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
return 0; 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 * Invoked on each preference click in this hierarchy, overrides
* PreferenceActivity's implementation. Used to make sure we track the * PreferenceActivity's implementation. Used to make sure we track the
@@ -299,9 +289,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
preferredNetworkMode); preferredNetworkMode);
mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode)); mButtonEnabledNetworks.setValue(Integer.toString(settingsNetworkMode));
return true; return true;
} else if (preference == mButtonDataRoam) {
// Do not disable the preference screen if the user clicks Data roaming.
return true;
} else if (preference == mEuiccSettingsPref) { } else if (preference == mEuiccSettingsPref) {
Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS); Intent intent = new Intent(EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);
startActivity(intent); startActivity(intent);
@@ -398,6 +385,7 @@ public class MobileNetworkFragment extends DashboardFragment implements
SubscriptionManager.INVALID_SUBSCRIPTION_ID); SubscriptionManager.INVALID_SUBSCRIPTION_ID);
use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId); use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
use(CdmaApnPreferenceController.class).init(mSubId); use(CdmaApnPreferenceController.class).init(mSubId);
use(CarrierPreferenceController.class).init(mSubId); use(CarrierPreferenceController.class).init(mSubId);
use(DataUsagePreferenceController.class).init(mSubId); use(DataUsagePreferenceController.class).init(mSubId);
@@ -446,13 +434,10 @@ public class MobileNetworkFragment extends DashboardFragment implements
//get UI object references //get UI object references
PreferenceScreen prefSet = getPreferenceScreen(); PreferenceScreen prefSet = getPreferenceScreen();
mButtonDataRoam = (RestrictedSwitchPreference) prefSet.findPreference(
BUTTON_ROAMING_KEY);
mButtonPreferredNetworkMode = (ListPreference) prefSet.findPreference( mButtonPreferredNetworkMode = (ListPreference) prefSet.findPreference(
BUTTON_PREFERED_NETWORK_MODE); BUTTON_PREFERED_NETWORK_MODE);
mButtonEnabledNetworks = (ListPreference) prefSet.findPreference( mButtonEnabledNetworks = (ListPreference) prefSet.findPreference(
BUTTON_ENABLED_NETWORKS_KEY); BUTTON_ENABLED_NETWORKS_KEY);
mButtonDataRoam.setOnPreferenceChangeListener(this);
mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY); mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY);
@@ -525,11 +510,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
// preferences. // preferences.
getPreferenceScreen().setEnabled(true); 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 if (getPreferenceScreen().findPreference(BUTTON_PREFERED_NETWORK_MODE) != null
|| getPreferenceScreen().findPreference(BUTTON_ENABLED_NETWORKS_KEY) != null) { || getPreferenceScreen().findPreference(BUTTON_ENABLED_NETWORKS_KEY) != null) {
updatePreferredNetworkUIFromDb(); updatePreferredNetworkUIFromDb();
@@ -579,25 +559,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
// android.R.id.home will be triggered in onOptionsItemSelected() // android.R.id.home will be triggered in onOptionsItemSelected()
actionBar.setDisplayHomeAsUpEnabled(true); 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() { private void updateBody() {
@@ -1038,42 +999,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
boolean enhanced4gMode = !mButton4glte.isChecked(); boolean enhanced4gMode = !mButton4glte.isChecked();
mButton4glte.setChecked(enhanced4gMode); mButton4glte.setChecked(enhanced4gMode);
mImsMgr.setEnhanced4gLteModeSetting(mButton4glte.isChecked()); 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) { } else if (preference == mVideoCallingPref) {
// If mButton4glte is not checked, mVideoCallingPref should be disabled. // If mButton4glte is not checked, mVideoCallingPref should be disabled.
// So it only makes sense to call phoneMgr.enableVideoCalling if it's checked. // 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) { if (preference == null) {
return MetricsProto.MetricsEvent.VIEW_UNKNOWN; return MetricsProto.MetricsEvent.VIEW_UNKNOWN;
} else if (preference == mButtonDataRoam) {
return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE;
} else if (preference == mLteDataServicePref) { } else if (preference == mLteDataServicePref) {
return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE; return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE;
} else if (preference == mButton4glte) { } else if (preference == mButton4glte) {

View File

@@ -23,11 +23,11 @@ import android.content.DialogInterface.OnClickListener;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager; import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -42,15 +42,14 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
private CarrierConfigManager mCarrierConfigManager; private CarrierConfigManager mCarrierConfigManager;
private int mSubId; private int mSubId;
/** public static RoamingDialogFragment newInstance(int subId) {
* The interface we expect a host activity to implement. final RoamingDialogFragment dialogFragment = new RoamingDialogFragment();
*/ Bundle args = new Bundle();
public interface RoamingDialogListener { args.putInt(SUB_ID_KEY, subId);
void onPositiveButtonClick(DialogFragment dialog); dialogFragment.setArguments(args);
}
// the host activity which implements the listening interface return dialogFragment;
private RoamingDialogListener mListener; }
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
@@ -58,14 +57,6 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
Bundle args = getArguments(); Bundle args = getArguments();
mSubId = args.getInt(SUB_ID_KEY); mSubId = args.getInt(SUB_ID_KEY);
mCarrierConfigManager = new CarrierConfigManager(context); mCarrierConfigManager = new CarrierConfigManager(context);
Fragment fragment = getTargetFragment();
try {
mListener = (RoamingDialogListener) fragment;
} catch (ClassCastException e) {
throw new ClassCastException(fragment.toString() +
"must implement RoamingDialogListener");
}
} }
@Override @Override
@@ -95,7 +86,8 @@ public class RoamingDialogFragment extends InstrumentedDialogFragment implements
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
// let the host know that the positive button has been clicked // let the host know that the positive button has been clicked
if (which == dialog.BUTTON_POSITIVE) { if (which == dialog.BUTTON_POSITIVE) {
mListener.onPositiveButtonClick(this); TelephonyManager.from(getContext()).createForSubscriptionId(
mSubId).setDataRoamingEnabled(true);
} }
} }
} }

View File

@@ -0,0 +1,181 @@
/*
* 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);
}
}
}

View File

@@ -0,0 +1,144 @@
/*
* 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();
}
}