blob: 940c67fc8b9ceed4dc26b7508e26853698a31b0a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.settings.datausage;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.icu.text.MeasureFormat;
import android.icu.util.MeasureUnit;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.NumberPicker;
import androidx.annotation.IntegerRes;
import androidx.annotation.VisibleForTesting;
import com.android.car.settings.R;
import com.android.car.ui.preference.CarUiDialogFragment;
/** Dialog that is used to pick the data usage warning/limit threshold bytes. */
public class UsageBytesThresholdPickerDialog extends CarUiDialogFragment {
/** Tag used to identify dialog in {@link androidx.fragment.app.FragmentManager}. */
public static final String TAG = "UsageBytesThresholdPickerDialog";
private static final String ARG_DIALOG_TITLE_RES = "arg_dialog_title_res";
private static final String ARG_CURRENT_THRESHOLD = "arg_current_threshold";
private static final float MB_GB_SUFFIX_THRESHOLD = 1.5f;
@VisibleForTesting
static final long MIB_IN_BYTES = 1024 * 1024;
@VisibleForTesting
static final long GIB_IN_BYTES = MIB_IN_BYTES * 1024;
@VisibleForTesting
static final long MAX_DATA_LIMIT_BYTES = 50000 * GIB_IN_BYTES;
// Number pickers can be used to pick strings as well.
private NumberPicker mBytesUnits;
private View mUpArrow;
private View mDownArrow;
private EditText mThresholdEditor;
private BytesThresholdPickedListener mBytesThresholdPickedListener;
private long mCurrentThreshold;
/**
* Creates a new instance of the {@link UsageBytesThresholdPickerDialog} with the
* {@code currentThreshold} represented with the best units available.
*/
public static UsageBytesThresholdPickerDialog newInstance(@IntegerRes int dialogTitle,
long currentThreshold) {
UsageBytesThresholdPickerDialog dialog = new UsageBytesThresholdPickerDialog();
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TITLE_RES, dialogTitle);
args.putLong(ARG_CURRENT_THRESHOLD, currentThreshold);
dialog.setArguments(args);
return dialog;
}
/** Sets a {@link BytesThresholdPickedListener}. */
public void setBytesThresholdPickedListener(
BytesThresholdPickedListener bytesThresholdPickedListener) {
mBytesThresholdPickedListener = bytesThresholdPickedListener;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
// Use builder context to keep consistent theme.
LayoutInflater inflater = LayoutInflater.from(builder.getContext());
View view = inflater.inflate(R.layout.usage_bytes_threshold_picker,
/* root= */ null, /* attachToRoot= */ false);
mCurrentThreshold = getArguments().getLong(ARG_CURRENT_THRESHOLD);
if (mCurrentThreshold < 0) {
mCurrentThreshold = 0;
}
MeasureFormat formatter = MeasureFormat.getInstance(
getContext().getResources().getConfiguration().locale,
MeasureFormat.FormatWidth.SHORT);
String[] units = new String[] {
formatter.getUnitDisplayName(MeasureUnit.MEGABYTE),
formatter.getUnitDisplayName(MeasureUnit.GIGABYTE)
};
mBytesUnits = view.findViewById(R.id.bytes_units);
mBytesUnits.setMinValue(0);
mBytesUnits.setMaxValue(units.length - 1);
mBytesUnits.setDisplayedValues(units);
mThresholdEditor = view.findViewById(R.id.bytes_threshold);
mUpArrow = view.findViewById(R.id.up_arrow_container);
mUpArrow.setOnClickListener(v -> mBytesUnits.setValue(mBytesUnits.getValue() - 1));
mDownArrow = view.findViewById(R.id.down_arrow_container);
mDownArrow.setOnClickListener(v -> mBytesUnits.setValue(mBytesUnits.getValue() + 1));
updateCurrentView(mCurrentThreshold);
return builder
.setTitle(getArguments().getInt(ARG_DIALOG_TITLE_RES))
.setView(view)
.setPositiveButton(R.string.usage_bytes_threshold_picker_positive_button,
/* onClickListener= */ this)
.create();
}
@Override
protected void onDialogClosed(boolean positiveResult) {
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
long newThreshold = getCurrentThreshold();
if (mBytesThresholdPickedListener != null
&& mCurrentThreshold != newThreshold) {
mBytesThresholdPickedListener.onThresholdPicked(newThreshold);
}
}
}
/** Gets the threshold currently represented by this {@link UsageBytesThresholdPickerDialog}. */
public long getCurrentThreshold() {
String bytesString = mThresholdEditor.getText().toString();
if (bytesString.isEmpty() || bytesString.equals(".")) {
bytesString = "0";
}
long bytes = (long) (Float.valueOf(bytesString) * (mBytesUnits.getValue() == 0
? MIB_IN_BYTES : GIB_IN_BYTES));
// To fix the overflow problem.
long correctedBytes = Math.min(MAX_DATA_LIMIT_BYTES, bytes);
return correctedBytes;
}
@VisibleForTesting
void setThresholdEditor(long threshold) {
updateCurrentView(threshold);
}
private void updateCurrentView(long threshold) {
String bytesText;
if (threshold > MB_GB_SUFFIX_THRESHOLD * GIB_IN_BYTES) {
bytesText = formatText(threshold / (float) GIB_IN_BYTES);
mBytesUnits.setValue(1);
} else {
bytesText = formatText(threshold / (float) MIB_IN_BYTES);
mBytesUnits.setValue(0);
}
mThresholdEditor.setText(bytesText);
mThresholdEditor.setSelection(0, bytesText.length());
}
private String formatText(float v) {
v = Math.round(v * 100) / 100f;
return String.valueOf(v);
}
/** A listener that is called when a date is selected. */
public interface BytesThresholdPickedListener {
/** A method that determines how to process the selected day of month. */
void onThresholdPicked(long numBytes);
}
}