Merge "Refactor MobileDataPreference"

This commit is contained in:
Lei Yu
2018-10-11 00:24:56 +00:00
committed by Android (Google) Code Review
10 changed files with 640 additions and 356 deletions

View File

@@ -16,6 +16,8 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto" xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="mobile_network_pref_screen"
android:title="@string/network_settings_title"
settings:initialExpandedChildrenCount="4"> settings:initialExpandedChildrenCount="4">
<PreferenceScreen <PreferenceScreen
@@ -23,10 +25,11 @@
android:title="@string/cdma_lte_data_service"> android:title="@string/cdma_lte_data_service">
</PreferenceScreen> </PreferenceScreen>
<com.android.settings.mobilenetwork.MobileDataPreference <SwitchPreference
android:key="mobile_data_enable" android:key="mobile_data_enable"
android:title="@string/mobile_data_settings_title" 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 <com.android.settingslib.RestrictedSwitchPreference
android:key="button_roaming_key" android:key="button_roaming_key"

View File

@@ -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);
}
}
}

View File

@@ -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];
}
};
}
}

View File

@@ -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);
}
}
}

View File

@@ -34,6 +34,7 @@ import android.os.Message;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.provider.Settings; import android.provider.Settings;
import android.telecom.PhoneAccountHandle; import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
@@ -61,8 +62,11 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference; 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 com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -156,7 +160,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
private Preference mWiFiCallingPref; private Preference mWiFiCallingPref;
private SwitchPreference mVideoCallingPref; private SwitchPreference mVideoCallingPref;
private NetworkSelectListPreference mButtonNetworkSelect; private NetworkSelectListPreference mButtonNetworkSelect;
private MobileDataPreference mMobileDataPref;
private DataUsagePreference mDataUsagePref; private DataUsagePreference mDataUsagePref;
private static final String iface = "rmnet0"; //TODO: this will go away private static final String iface = "rmnet0"; //TODO: this will go away
@@ -238,6 +241,9 @@ public class MobileNetworkFragment extends DashboardFragment implements
*/ */
@Override @Override
public boolean onPreferenceTreeClick(Preference preference) { public boolean onPreferenceTreeClick(Preference preference) {
if (super.onPreferenceTreeClick(preference)) {
return true;
}
sendMetricsEventPreferenceClicked(getPreferenceScreen(), preference); sendMetricsEventPreferenceClicked(getPreferenceScreen(), preference);
/** TODO: Refactor and get rid of the if's using subclasses */ /** TODO: Refactor and get rid of the if's using subclasses */
@@ -298,7 +304,7 @@ public class MobileNetworkFragment extends DashboardFragment implements
startActivity(intent); startActivity(intent);
return true; return true;
} else if (preference == mWiFiCallingPref || preference == mVideoCallingPref } else if (preference == mWiFiCallingPref || preference == mVideoCallingPref
|| preference == mMobileDataPref || preference == mDataUsagePref) { || preference == mDataUsagePref) {
return false; return false;
} else { } else {
// if the button is anything but the simple toggle preference, // if the button is anything but the simple toggle preference,
@@ -383,6 +389,15 @@ public class MobileNetworkFragment extends DashboardFragment implements
mPhoneStateListener.updateSubscriptionId(mSubId); 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 @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
Log.i(LOG_TAG, "onCreate:+"); Log.i(LOG_TAG, "onCreate:+");
@@ -407,7 +422,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY); mCallingCategory = (PreferenceCategory) findPreference(CATEGORY_CALLING_KEY);
mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY); mWiFiCallingPref = findPreference(BUTTON_WIFI_CALLING_KEY);
mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY); mVideoCallingPref = (SwitchPreference) findPreference(BUTTON_VIDEO_CALLING_KEY);
mMobileDataPref = (MobileDataPreference) findPreference(BUTTON_MOBILE_DATA_ENABLE_KEY);
mDataUsagePref = (DataUsagePreference) findPreference(BUTTON_DATA_USAGE_KEY); mDataUsagePref = (DataUsagePreference) findPreference(BUTTON_DATA_USAGE_KEY);
try { try {
@@ -439,8 +453,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
// Initialize mActiveSubInfo // Initialize mActiveSubInfo
int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); int max = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
mActiveSubInfos = mSubscriptionManager.getActiveSubscriptionInfoList(); mActiveSubInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
mSubId = getArguments().getInt(MobileSettingsActivity.KEY_SUBSCRIPTION_ID,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
updatePhone(); updatePhone();
if (hasActiveSubscriptions()) { if (hasActiveSubscriptions()) {
@@ -490,14 +502,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
} }
} }
@Override
public void onDestroy() {
super.onDestroy();
if (mMobileDataPref != null) {
mMobileDataPref.dispose();
}
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@@ -567,17 +571,14 @@ public class MobileNetworkFragment extends DashboardFragment implements
actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true);
} }
prefSet.addPreference(mMobileDataPref);
prefSet.addPreference(mButtonDataRoam); prefSet.addPreference(mButtonDataRoam);
prefSet.addPreference(mDataUsagePref); prefSet.addPreference(mDataUsagePref);
mMobileDataPref.setEnabled(hasActiveSubscriptions);
mButtonDataRoam.setEnabled(hasActiveSubscriptions); mButtonDataRoam.setEnabled(hasActiveSubscriptions);
mDataUsagePref.setEnabled(hasActiveSubscriptions); mDataUsagePref.setEnabled(hasActiveSubscriptions);
if (hasActiveSubscriptions) { if (hasActiveSubscriptions) {
// Customized preferences needs to be initialized with subId. // Customized preferences needs to be initialized with subId.
mMobileDataPref.initialize(phoneSubId);
mDataUsagePref.initialize(phoneSubId); mDataUsagePref.initialize(phoneSubId);
// Initialize states of mButtonDataRoam. // Initialize states of mButtonDataRoam.
@@ -609,8 +610,6 @@ public class MobileNetworkFragment extends DashboardFragment implements
return; return;
} }
prefSet.removeAll();
updateBodyBasicFields(activity, prefSet, mSubId, hasActiveSubscriptions); updateBodyBasicFields(activity, prefSet, mSubId, hasActiveSubscriptions);
if (hasActiveSubscriptions) { if (hasActiveSubscriptions) {
@@ -1751,8 +1750,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 == mMobileDataPref) {
return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE;
} else if (preference == mButtonDataRoam) { } else if (preference == mButtonDataRoam) {
return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE; return MetricsProto.MetricsEvent.ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE;
} else if (preference == mDataUsagePref) { } else if (preference == mDataUsagePref) {
@@ -1864,6 +1861,17 @@ public class MobileNetworkFragment extends DashboardFragment implements
protected boolean isPageSearchEnabled(Context context) { protected boolean isPageSearchEnabled(Context context) {
return false; 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> { private static final class SetPreferredNetworkAsyncTask extends AsyncTask<Void, Void, Boolean> {

View File

@@ -22,13 +22,14 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor; import android.database.Cursor;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.provider.Settings; import android.provider.Settings;
import android.telecom.PhoneAccountHandle; import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager; import android.telephony.euicc.EuiccManager;
import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.ImsFeature;
@@ -170,4 +171,30 @@ public class MobileNetworkUtils {
//TODO(b/114749736): get carrier config from subId //TODO(b/114749736): get carrier config from subId
return new PersistableBundle(); 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);
}
}
}
}
}
} }

View File

@@ -23,6 +23,11 @@ import android.telephony.SubscriptionManager;
import android.view.Menu; import android.view.Menu;
import android.view.View; 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.internal.util.CollectionUtils;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.SettingsBaseActivity; import com.android.settings.core.SettingsBaseActivity;
@@ -31,11 +36,6 @@ import com.google.android.material.bottomnavigation.BottomNavigationView;
import java.util.List; 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 { public class MobileSettingsActivity extends SettingsBaseActivity {
@VisibleForTesting @VisibleForTesting

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -30,6 +30,10 @@ import android.telephony.SubscriptionManager;
import android.view.Menu; import android.view.Menu;
import android.view.View; 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.internal.view.menu.ContextMenuBuilder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -46,10 +50,6 @@ import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
public class MobileSettingsActivityTest { public class MobileSettingsActivityTest {