This commit *only* changes imports and optimize imports. We don't do anything else. This patch can't compile pass and run test case. We will update other patches to fix these problem. Change list. 1. import android.app.Fragment; -> import androidx.fragment.app.Fragment; 2. import android.app.DialogFragment; -> import androidx.fragment.app.DialogFragment; 3. import android.app.ListFragment; -> import androidx.fragment.app.ListFragment; 4. import android.app.LoaderManager; -> import androidx.loader.app.LoaderManager; 5. import android.content.AsyncTaskLoader; -> import androidx.loader.content.AsyncTaskLoader; 6. import android.content.Loader; -> import androidx.loader.content.Loader; 7. import android.app.FragmentTransaction; -> import androidx.fragment.app.FragmentTransaction; 8. import android.app.FragmentManager; -> import androidx.fragment.app.FragmentManager; 9. import android.app.LoaderManager.LoaderCallbacks; -> import androidx.loader.app.LoaderManager.LoaderCallbacks; Bug: 110259478 Test: Can't test it. Change-Id: I0a3f98fff34a3494a839c3c42aeabcec3df2c8b3
482 lines
19 KiB
Java
482 lines
19 KiB
Java
/*
|
|
* Copyright (C) 2016 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.datausage;
|
|
|
|
import static android.net.NetworkPolicy.LIMIT_DISABLED;
|
|
import static android.net.NetworkPolicy.WARNING_DISABLED;
|
|
|
|
import android.app.AlertDialog;
|
|
import android.app.Dialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.res.Resources;
|
|
import android.net.NetworkPolicy;
|
|
import android.net.NetworkTemplate;
|
|
import android.os.Bundle;
|
|
import android.provider.SearchIndexableResource;
|
|
import android.text.format.Time;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.widget.EditText;
|
|
import android.widget.NumberPicker;
|
|
import android.widget.Spinner;
|
|
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
|
import com.android.settings.R;
|
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
|
import com.android.settings.search.BaseSearchIndexProvider;
|
|
import com.android.settings.search.Indexable;
|
|
import com.android.settingslib.NetworkPolicyEditor;
|
|
import com.android.settingslib.net.DataUsageController;
|
|
import com.android.settingslib.search.SearchIndexable;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import androidx.fragment.app.Fragment;
|
|
import androidx.preference.Preference;
|
|
import androidx.preference.SwitchPreference;
|
|
|
|
@SearchIndexable
|
|
public class BillingCycleSettings extends DataUsageBase implements
|
|
Preference.OnPreferenceChangeListener, DataUsageEditController {
|
|
|
|
private static final String TAG = "BillingCycleSettings";
|
|
private static final boolean LOGD = false;
|
|
public static final long MIB_IN_BYTES = 1024 * 1024;
|
|
public static final long GIB_IN_BYTES = MIB_IN_BYTES * 1024;
|
|
|
|
private static final long MAX_DATA_LIMIT_BYTES = 50000 * GIB_IN_BYTES;
|
|
|
|
private static final String TAG_CONFIRM_LIMIT = "confirmLimit";
|
|
private static final String TAG_CYCLE_EDITOR = "cycleEditor";
|
|
private static final String TAG_WARNING_EDITOR = "warningEditor";
|
|
|
|
private static final String KEY_BILLING_CYCLE = "billing_cycle";
|
|
private static final String KEY_SET_DATA_WARNING = "set_data_warning";
|
|
private static final String KEY_DATA_WARNING = "data_warning";
|
|
@VisibleForTesting
|
|
static final String KEY_SET_DATA_LIMIT = "set_data_limit";
|
|
private static final String KEY_DATA_LIMIT = "data_limit";
|
|
|
|
private NetworkTemplate mNetworkTemplate;
|
|
private Preference mBillingCycle;
|
|
private Preference mDataWarning;
|
|
private SwitchPreference mEnableDataWarning;
|
|
private SwitchPreference mEnableDataLimit;
|
|
private Preference mDataLimit;
|
|
private DataUsageController mDataUsageController;
|
|
|
|
@VisibleForTesting
|
|
void setUpForTest(NetworkPolicyEditor policyEditor,
|
|
Preference billingCycle,
|
|
Preference dataLimit,
|
|
Preference dataWarning,
|
|
SwitchPreference enableLimit,
|
|
SwitchPreference enableWarning) {
|
|
services.mPolicyEditor = policyEditor;
|
|
mBillingCycle = billingCycle;
|
|
mDataLimit = dataLimit;
|
|
mDataWarning = dataWarning;
|
|
mEnableDataLimit = enableLimit;
|
|
mEnableDataWarning = enableWarning;
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle icicle) {
|
|
super.onCreate(icicle);
|
|
|
|
mDataUsageController = new DataUsageController(getContext());
|
|
|
|
Bundle args = getArguments();
|
|
mNetworkTemplate = args.getParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE);
|
|
|
|
addPreferencesFromResource(R.xml.billing_cycle);
|
|
mBillingCycle = findPreference(KEY_BILLING_CYCLE);
|
|
mEnableDataWarning = (SwitchPreference) findPreference(KEY_SET_DATA_WARNING);
|
|
mEnableDataWarning.setOnPreferenceChangeListener(this);
|
|
mDataWarning = findPreference(KEY_DATA_WARNING);
|
|
mEnableDataLimit = (SwitchPreference) findPreference(KEY_SET_DATA_LIMIT);
|
|
mEnableDataLimit.setOnPreferenceChangeListener(this);
|
|
mDataLimit = findPreference(KEY_DATA_LIMIT);
|
|
|
|
mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.data_warning_footnote);
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
updatePrefs();
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void updatePrefs() {
|
|
mBillingCycle.setSummary(null);
|
|
final long warningBytes = services.mPolicyEditor.getPolicyWarningBytes(mNetworkTemplate);
|
|
if (warningBytes != WARNING_DISABLED) {
|
|
mDataWarning.setSummary(DataUsageUtils.formatDataUsage(getContext(), warningBytes));
|
|
mDataWarning.setEnabled(true);
|
|
mEnableDataWarning.setChecked(true);
|
|
} else {
|
|
mDataWarning.setSummary(null);
|
|
mDataWarning.setEnabled(false);
|
|
mEnableDataWarning.setChecked(false);
|
|
}
|
|
final long limitBytes = services.mPolicyEditor.getPolicyLimitBytes(mNetworkTemplate);
|
|
if (limitBytes != LIMIT_DISABLED) {
|
|
mDataLimit.setSummary(DataUsageUtils.formatDataUsage(getContext(), limitBytes));
|
|
mDataLimit.setEnabled(true);
|
|
mEnableDataLimit.setChecked(true);
|
|
} else {
|
|
mDataLimit.setSummary(null);
|
|
mDataLimit.setEnabled(false);
|
|
mEnableDataLimit.setChecked(false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreferenceTreeClick(Preference preference) {
|
|
if (preference == mBillingCycle) {
|
|
CycleEditorFragment.show(this);
|
|
return true;
|
|
} else if (preference == mDataWarning) {
|
|
BytesEditorFragment.show(this, false);
|
|
return true;
|
|
} else if (preference == mDataLimit) {
|
|
BytesEditorFragment.show(this, true);
|
|
return true;
|
|
}
|
|
return super.onPreferenceTreeClick(preference);
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
if (mEnableDataLimit == preference) {
|
|
boolean enabled = (Boolean) newValue;
|
|
if (!enabled) {
|
|
setPolicyLimitBytes(LIMIT_DISABLED);
|
|
return true;
|
|
}
|
|
ConfirmLimitFragment.show(this);
|
|
// This preference is enabled / disabled by ConfirmLimitFragment.
|
|
return false;
|
|
} else if (mEnableDataWarning == preference) {
|
|
boolean enabled = (Boolean) newValue;
|
|
if (enabled) {
|
|
setPolicyWarningBytes(mDataUsageController.getDefaultWarningLevel());
|
|
} else {
|
|
setPolicyWarningBytes(WARNING_DISABLED);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.BILLING_CYCLE;
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void setPolicyLimitBytes(long limitBytes) {
|
|
if (LOGD) Log.d(TAG, "setPolicyLimitBytes()");
|
|
services.mPolicyEditor.setPolicyLimitBytes(mNetworkTemplate, limitBytes);
|
|
updatePrefs();
|
|
}
|
|
|
|
private void setPolicyWarningBytes(long warningBytes) {
|
|
if (LOGD) Log.d(TAG, "setPolicyWarningBytes()");
|
|
services.mPolicyEditor.setPolicyWarningBytes(mNetworkTemplate, warningBytes);
|
|
updatePrefs();
|
|
}
|
|
|
|
@Override
|
|
public NetworkPolicyEditor getNetworkPolicyEditor() {
|
|
return services.mPolicyEditor;
|
|
}
|
|
|
|
@Override
|
|
public NetworkTemplate getNetworkTemplate() {
|
|
return mNetworkTemplate;
|
|
}
|
|
|
|
@Override
|
|
public void updateDataUsage() {
|
|
updatePrefs();
|
|
}
|
|
|
|
/**
|
|
* Dialog to edit {@link NetworkPolicy#warningBytes}.
|
|
*/
|
|
public static class BytesEditorFragment extends InstrumentedDialogFragment
|
|
implements DialogInterface.OnClickListener {
|
|
private static final String EXTRA_TEMPLATE = "template";
|
|
private static final String EXTRA_LIMIT = "limit";
|
|
private View mView;
|
|
|
|
public static void show(DataUsageEditController parent, boolean isLimit) {
|
|
if (!(parent instanceof Fragment)) {
|
|
return;
|
|
}
|
|
Fragment targetFragment = (Fragment) parent;
|
|
if (!targetFragment.isAdded()) {
|
|
return;
|
|
}
|
|
|
|
final Bundle args = new Bundle();
|
|
args.putParcelable(EXTRA_TEMPLATE, parent.getNetworkTemplate());
|
|
args.putBoolean(EXTRA_LIMIT, isLimit);
|
|
|
|
final BytesEditorFragment dialog = new BytesEditorFragment();
|
|
dialog.setArguments(args);
|
|
dialog.setTargetFragment(targetFragment, 0);
|
|
dialog.show(targetFragment.getFragmentManager(), TAG_WARNING_EDITOR);
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
final Context context = getActivity();
|
|
final LayoutInflater dialogInflater = LayoutInflater.from(context);
|
|
final boolean isLimit = getArguments().getBoolean(EXTRA_LIMIT);
|
|
mView = dialogInflater.inflate(R.layout.data_usage_bytes_editor, null, false);
|
|
setupPicker((EditText) mView.findViewById(R.id.bytes),
|
|
(Spinner) mView.findViewById(R.id.size_spinner));
|
|
return new AlertDialog.Builder(context)
|
|
.setTitle(isLimit ? R.string.data_usage_limit_editor_title
|
|
: R.string.data_usage_warning_editor_title)
|
|
.setView(mView)
|
|
.setPositiveButton(R.string.data_usage_cycle_editor_positive, this)
|
|
.create();
|
|
}
|
|
|
|
private void setupPicker(EditText bytesPicker, Spinner type) {
|
|
final DataUsageEditController target = (DataUsageEditController) getTargetFragment();
|
|
final NetworkPolicyEditor editor = target.getNetworkPolicyEditor();
|
|
|
|
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
|
|
final boolean isLimit = getArguments().getBoolean(EXTRA_LIMIT);
|
|
final long bytes = isLimit ? editor.getPolicyLimitBytes(template)
|
|
: editor.getPolicyWarningBytes(template);
|
|
final long limitDisabled = isLimit ? LIMIT_DISABLED : WARNING_DISABLED;
|
|
|
|
if (bytes > 1.5f * GIB_IN_BYTES) {
|
|
final String bytesText = formatText(bytes / (float) GIB_IN_BYTES);
|
|
bytesPicker.setText(bytesText);
|
|
bytesPicker.setSelection(0, bytesText.length());
|
|
|
|
type.setSelection(1);
|
|
} else {
|
|
final String bytesText = formatText(bytes / (float) MIB_IN_BYTES);
|
|
bytesPicker.setText(bytesText);
|
|
bytesPicker.setSelection(0, bytesText.length());
|
|
|
|
type.setSelection(0);
|
|
}
|
|
}
|
|
|
|
private String formatText(float v) {
|
|
v = Math.round(v * 100) / 100f;
|
|
return String.valueOf(v);
|
|
}
|
|
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
if (which != DialogInterface.BUTTON_POSITIVE) {
|
|
return;
|
|
}
|
|
final DataUsageEditController target = (DataUsageEditController) getTargetFragment();
|
|
final NetworkPolicyEditor editor = target.getNetworkPolicyEditor();
|
|
|
|
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
|
|
final boolean isLimit = getArguments().getBoolean(EXTRA_LIMIT);
|
|
EditText bytesField = (EditText) mView.findViewById(R.id.bytes);
|
|
Spinner spinner = (Spinner) mView.findViewById(R.id.size_spinner);
|
|
|
|
String bytesString = bytesField.getText().toString();
|
|
if (bytesString.isEmpty() || bytesString.equals(".")) {
|
|
bytesString = "0";
|
|
}
|
|
final long bytes = (long) (Float.valueOf(bytesString)
|
|
* (spinner.getSelectedItemPosition() == 0 ? MIB_IN_BYTES : GIB_IN_BYTES));
|
|
|
|
// to fix the overflow problem
|
|
final long correctedBytes = Math.min(MAX_DATA_LIMIT_BYTES, bytes);
|
|
if (isLimit) {
|
|
editor.setPolicyLimitBytes(template, correctedBytes);
|
|
} else {
|
|
editor.setPolicyWarningBytes(template, correctedBytes);
|
|
}
|
|
target.updateDataUsage();
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.DIALOG_BILLING_BYTE_LIMIT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dialog to edit {@link NetworkPolicy}.
|
|
*/
|
|
public static class CycleEditorFragment extends InstrumentedDialogFragment implements
|
|
DialogInterface.OnClickListener {
|
|
private static final String EXTRA_TEMPLATE = "template";
|
|
private NumberPicker mCycleDayPicker;
|
|
|
|
public static void show(BillingCycleSettings parent) {
|
|
if (!parent.isAdded()) return;
|
|
|
|
final Bundle args = new Bundle();
|
|
args.putParcelable(EXTRA_TEMPLATE, parent.mNetworkTemplate);
|
|
|
|
final CycleEditorFragment dialog = new CycleEditorFragment();
|
|
dialog.setArguments(args);
|
|
dialog.setTargetFragment(parent, 0);
|
|
dialog.show(parent.getFragmentManager(), TAG_CYCLE_EDITOR);
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.DIALOG_BILLING_CYCLE;
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
final Context context = getActivity();
|
|
final DataUsageEditController target = (DataUsageEditController) getTargetFragment();
|
|
final NetworkPolicyEditor editor = target.getNetworkPolicyEditor();
|
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
|
final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
|
|
|
|
final View view = dialogInflater.inflate(R.layout.data_usage_cycle_editor, null, false);
|
|
mCycleDayPicker = (NumberPicker) view.findViewById(R.id.cycle_day);
|
|
|
|
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
|
|
final int cycleDay = editor.getPolicyCycleDay(template);
|
|
|
|
mCycleDayPicker.setMinValue(1);
|
|
mCycleDayPicker.setMaxValue(31);
|
|
mCycleDayPicker.setValue(cycleDay);
|
|
mCycleDayPicker.setWrapSelectorWheel(true);
|
|
|
|
return builder.setTitle(R.string.data_usage_cycle_editor_title)
|
|
.setView(view)
|
|
.setPositiveButton(R.string.data_usage_cycle_editor_positive, this)
|
|
.create();
|
|
}
|
|
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
final NetworkTemplate template = getArguments().getParcelable(EXTRA_TEMPLATE);
|
|
final DataUsageEditController target = (DataUsageEditController) getTargetFragment();
|
|
final NetworkPolicyEditor editor = target.getNetworkPolicyEditor();
|
|
|
|
// clear focus to finish pending text edits
|
|
mCycleDayPicker.clearFocus();
|
|
|
|
final int cycleDay = mCycleDayPicker.getValue();
|
|
final String cycleTimezone = new Time().timezone;
|
|
editor.setPolicyCycleDay(template, cycleDay, cycleTimezone);
|
|
target.updateDataUsage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dialog to request user confirmation before setting
|
|
* {@link NetworkPolicy#limitBytes}.
|
|
*/
|
|
public static class ConfirmLimitFragment extends InstrumentedDialogFragment implements
|
|
DialogInterface.OnClickListener {
|
|
@VisibleForTesting
|
|
static final String EXTRA_LIMIT_BYTES = "limitBytes";
|
|
public static final float FLOAT = 1.2f;
|
|
|
|
public static void show(BillingCycleSettings parent) {
|
|
if (!parent.isAdded()) return;
|
|
|
|
final NetworkPolicy policy = parent.services.mPolicyEditor
|
|
.getPolicy(parent.mNetworkTemplate);
|
|
if (policy == null) return;
|
|
|
|
final Resources res = parent.getResources();
|
|
final long minLimitBytes = (long) (policy.warningBytes * FLOAT);
|
|
final long limitBytes;
|
|
|
|
// TODO: customize default limits based on network template
|
|
limitBytes = Math.max(5 * GIB_IN_BYTES, minLimitBytes);
|
|
|
|
final Bundle args = new Bundle();
|
|
args.putLong(EXTRA_LIMIT_BYTES, limitBytes);
|
|
|
|
final ConfirmLimitFragment dialog = new ConfirmLimitFragment();
|
|
dialog.setArguments(args);
|
|
dialog.setTargetFragment(parent, 0);
|
|
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_LIMIT);
|
|
}
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.DIALOG_BILLING_CONFIRM_LIMIT;
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
final Context context = getActivity();
|
|
|
|
return new AlertDialog.Builder(context)
|
|
.setTitle(R.string.data_usage_limit_dialog_title)
|
|
.setMessage(R.string.data_usage_limit_dialog_mobile)
|
|
.setPositiveButton(android.R.string.ok, this)
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.create();
|
|
}
|
|
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
final BillingCycleSettings target = (BillingCycleSettings) getTargetFragment();
|
|
if (which != DialogInterface.BUTTON_POSITIVE) return;
|
|
final long limitBytes = getArguments().getLong(EXTRA_LIMIT_BYTES);
|
|
if (target != null) {
|
|
target.setPolicyLimitBytes(limitBytes);
|
|
}
|
|
target.getPreferenceManager().getSharedPreferences().edit()
|
|
.putBoolean(KEY_SET_DATA_LIMIT, true).apply();
|
|
}
|
|
}
|
|
|
|
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
|
new BaseSearchIndexProvider() {
|
|
@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.billing_cycle;
|
|
result.add(sir);
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
protected boolean isPageSearchEnabled(Context context) {
|
|
return DataUsageUtils.hasMobileData(context);
|
|
}
|
|
};
|
|
|
|
}
|