Refactor MobileDataPreference
1. Remove it and change it to SwitchPrference
2. Build MobileDataDialogFragment to show dialog when needed
3. Create controller for it to decide when to launch the dialog
Bug: 114749736
Test: RunSettingsRoboTests
Change-Id: I02b9662c5829e765f2c71d10ed951d792cf7aaa1
diff --git a/res/xml/network_setting_fragment.xml b/res/xml/network_setting_fragment.xml
index c383ab6..396f2e4 100644
--- a/res/xml/network_setting_fragment.xml
+++ b/res/xml/network_setting_fragment.xml
@@ -16,6 +16,8 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="mobile_network_pref_screen"
+ android:title="@string/network_settings_title"
settings:initialExpandedChildrenCount="4">
<PreferenceScreen
@@ -23,10 +25,11 @@
android:title="@string/cdma_lte_data_service">
</PreferenceScreen>
- <com.android.settings.mobilenetwork.MobileDataPreference
+ <SwitchPreference
android:key="mobile_data_enable"
android:title="@string/mobile_data_settings_title"
- android:summary="@string/mobile_data_settings_summary"/>
+ android:summary="@string/mobile_data_settings_summary"
+ settings:controller="com.android.settings.mobilenetwork.MobileDataPreferenceController"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="button_roaming_key"
diff --git a/src/com/android/settings/mobilenetwork/MobileDataDialogFragment.java b/src/com/android/settings/mobilenetwork/MobileDataDialogFragment.java
new file mode 100644
index 0000000..86a5518
--- /dev/null
+++ b/src/com/android/settings/mobilenetwork/MobileDataDialogFragment.java
@@ -0,0 +1,133 @@
+/*
+ * 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.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+
+/**
+ * Dialog Fragment to show dialog for "mobile data"
+ *
+ * 1. When user want to disable data in single sim case, show dialog to confirm
+ * 2. When user want to enable data in multiple sim case, show dialog to confirm to disable other
+ * sim
+ */
+public class MobileDataDialogFragment extends InstrumentedDialogFragment implements
+ DialogInterface.OnClickListener {
+
+ public static final int TYPE_DISABLE_DIALOG = 0;
+ public static final int TYPE_MULTI_SIM_DIALOG = 1;
+
+ private static final String ARG_DIALOG_TYPE = "dialog_type";
+ private static final String ARG_SUB_ID = "subId";
+
+ private SubscriptionManager mSubscriptionManager;
+ private int mType;
+ private int mSubId;
+
+ public static MobileDataDialogFragment newInstance(int type, int subId) {
+ final MobileDataDialogFragment dialogFragment = new MobileDataDialogFragment();
+
+ Bundle args = new Bundle();
+ args.putInt(ARG_DIALOG_TYPE, type);
+ args.putInt(ARG_SUB_ID, subId);
+ dialogFragment.setArguments(args);
+
+ return dialogFragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mSubscriptionManager = getContext().getSystemService(SubscriptionManager.class);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Bundle bundle = getArguments();
+ final Context context = getContext();
+
+ mType = bundle.getInt(ARG_DIALOG_TYPE);
+ mSubId = bundle.getInt(ARG_SUB_ID);
+
+ switch (mType) {
+ case TYPE_DISABLE_DIALOG:
+ return new AlertDialog.Builder(context)
+ .setMessage(R.string.data_usage_disable_mobile)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ case TYPE_MULTI_SIM_DIALOG:
+ final SubscriptionInfo currentSubInfo =
+ mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
+ final SubscriptionInfo nextSubInfo =
+ mSubscriptionManager.getDefaultDataSubscriptionInfo();
+
+ final String previousName = (nextSubInfo == null)
+ ? getContext().getResources().getString(
+ R.string.sim_selection_required_pref)
+ : nextSubInfo.getDisplayName().toString();
+
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.sim_change_data_title)
+ .setMessage(context.getString(R.string.sim_change_data_message,
+ currentSubInfo != null
+ ? currentSubInfo.getDisplayName()
+ : "",
+ previousName))
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(R.string.cancel, null)
+ .create();
+ default:
+ throw new IllegalArgumentException("unknown type " + mType);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ //TODO(b/114749736): add metric id for this fragment
+ return 0;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (mType) {
+ case TYPE_DISABLE_DIALOG:
+ MobileNetworkUtils.setMobileDataEnabled(getContext(), mSubId, false /* enabled */,
+ false /* disableOtherSubscriptions */);
+ break;
+ case TYPE_MULTI_SIM_DIALOG:
+ mSubscriptionManager.setDefaultDataSubId(mSubId);
+ MobileNetworkUtils.setMobileDataEnabled(getContext(), mSubId, true /* enabled */,
+ true /* disableOtherSubscriptions */);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown type " + mType);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/mobilenetwork/MobileDataPreference.java b/src/com/android/settings/mobilenetwork/MobileDataPreference.java
deleted file mode 100644
index 37ce5a6..0000000
--- a/src/com/android/settings/mobilenetwork/MobileDataPreference.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * 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.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.Settings.Global;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.Checkable;
-
-import androidx.preference.DialogPreference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-
-import java.util.List;
-
-/**
- * Customized Preference to enable / disable mobile data.
- * Basically copy of with com.android.settings.CellDataPreference.
- */
-public class MobileDataPreference extends DialogPreference implements
- DialogInterface.OnClickListener {
-
- private static final boolean DBG = false;
- private static final String TAG = "MobileDataPreference";
-
- public int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- public boolean mChecked;
- // Whether to show the dialog to ask switching default data subscription.
- // Should be true only when a multi-sim phone only supports data connection on a single phone,
- // and user is enabling data on the non-default phone.
- public boolean mMultiSimDialog;
- private TelephonyManager mTelephonyManager;
- private SubscriptionManager mSubscriptionManager;
-
- public MobileDataPreference(Context context, AttributeSet attrs) {
- super(context, attrs, com.android.internal.R.attr.switchPreferenceStyle);
- }
-
- // Must be called to avoid binder leakage.
- void dispose() {
- mListener.setListener(false, mSubId, getContext());
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable s) {
- CellDataState state = (CellDataState) s;
- super.onRestoreInstanceState(state.getSuperState());
- mTelephonyManager = TelephonyManager.from(getContext());
- mChecked = state.mChecked;
- mMultiSimDialog = state.mMultiSimDialog;
- if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- mSubId = state.mSubId;
- setKey(getKey() + mSubId);
- }
- notifyChanged();
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- CellDataState state = new CellDataState(super.onSaveInstanceState());
- state.mChecked = mChecked;
- state.mMultiSimDialog = mMultiSimDialog;
- state.mSubId = mSubId;
- return state;
- }
-
- @Override
- public void onAttached() {
- super.onAttached();
- mListener.setListener(true, mSubId, getContext());
- }
-
- @Override
- protected void onPrepareForRemoval() {
- mListener.setListener(false, mSubId, getContext());
- super.onPrepareForRemoval();
- }
-
- /**
- * Initialize this preference with subId.
- */
- public void initialize(int subId) {
- if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- throw new IllegalArgumentException("MobileDataPreference needs a SubscriptionInfo");
- }
- mSubscriptionManager = SubscriptionManager.from(getContext());
- mTelephonyManager = TelephonyManager.from(getContext());
- if (mSubId != subId) {
- mSubId = subId;
- setKey(getKey() + subId);
- }
- updateChecked();
- }
-
- private void updateChecked() {
- setChecked(mTelephonyManager.getDataEnabled(mSubId));
- }
-
- @Override
- public void performClick() {
- if (!isEnabled() || !SubscriptionManager.isValidSubscriptionId(mSubId)) {
- return;
- }
- 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 (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<SubscriptionInfo> 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<CellDataState> CREATOR = new Creator<CellDataState>() {
- @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 0000000..c341d7e
--- /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 d8df8fa..b31d4d2 100644
--- a/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java
+++ b/src/com/android/settings/mobilenetwork/MobileNetworkFragment.java
@@ -34,6 +34,7 @@
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.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 @@
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 @@
*/
@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 @@
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,
@@ -384,6 +390,15 @@
}
@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:+");
super.onCreate(icicle);
@@ -407,7 +422,6 @@
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 @@
// Initialize mActiveSubInfo
int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
mActiveSubInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
- mSubId = getArguments().getInt(MobileSettingsActivity.KEY_SUBSCRIPTION_ID,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
updatePhone();
if (hasActiveSubscriptions()) {
@@ -491,14 +503,6 @@
}
@Override
- public void onDestroy() {
- super.onDestroy();
- if (mMobileDataPref != null) {
- mMobileDataPref.dispose();
- }
- }
-
- @Override
public void onResume() {
super.onResume();
Log.i(LOG_TAG, "onResume:+");
@@ -567,17 +571,14 @@
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 @@
return;
}
- prefSet.removeAll();
-
updateBodyBasicFields(activity, prefSet, mSubId, hasActiveSubscriptions);
if (hasActiveSubscriptions) {
@@ -1751,8 +1750,6 @@
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 @@
protected boolean isPageSearchEnabled(Context context) {
return false;
}
+
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final ArrayList<SearchIndexableResource> 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<Void, Void, Boolean> {
diff --git a/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java b/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java
index 2109375..44b1cef 100644
--- a/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java
+++ b/src/com/android/settings/mobilenetwork/MobileNetworkUtils.java
@@ -22,13 +22,14 @@
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 @@
//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<SubscriptionInfo> 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 37a180c..ba92ebf 100644
--- a/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java
+++ b/src/com/android/settings/mobilenetwork/MobileSettingsActivity.java
@@ -23,6 +23,11 @@
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 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 0000000..9bf9b54
--- /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 0000000..2b21f1f
--- /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 cb86d6f..a5a26b4 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.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 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 {