blob: 17b5ece0d2f30451cced0c578e2e5c7e4ebfe3b7 [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.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.NumberPicker;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.DialogFragment;
import com.android.car.settings.R;
/** Dialog that is used to pick the start day of month to track a data usage cycle. */
public class UsageCycleResetDayOfMonthPickerDialog extends DialogFragment {
private static final String ARG_SELECTED_DAY_OF_MONTH = "arg_selected_day_of_month";
/**
* Defines the time frequency at which touch listener should be triggered when holding either
* arrow button.
*/
@VisibleForTesting
static final int TIME_INTERVAL_MILLIS = 250;
private static final int MIN_DAY = 1;
private static final int MAX_DAY = 31;
private ResetDayOfMonthPickedListener mResetDayOfMonthPickedListener;
private NumberPicker mCycleDayOfMonthPicker;
private View mUpArrow;
private View mDownArrow;
/**
* Creates a new instance of the {@link UsageCycleResetDayOfMonthPickerDialog} with the {@link
* NumberPicker} set to showing the value {@code startDayOfMonth}.
*/
public static UsageCycleResetDayOfMonthPickerDialog newInstance(int startDayOfMonth) {
UsageCycleResetDayOfMonthPickerDialog dialog = new UsageCycleResetDayOfMonthPickerDialog();
Bundle args = new Bundle();
args.putInt(ARG_SELECTED_DAY_OF_MONTH, startDayOfMonth);
dialog.setArguments(args);
return dialog;
}
/** Sets a {@link ResetDayOfMonthPickedListener}. */
public void setResetDayOfMonthPickedListener(
ResetDayOfMonthPickedListener resetDayOfMonthPickedListener) {
mResetDayOfMonthPickedListener = resetDayOfMonthPickedListener;
}
@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_cycle_reset_day_of_month_picker,
/* root= */ null, /* attachToRoot= */ false);
int cycleDayOfMonth = getArguments().getInt(ARG_SELECTED_DAY_OF_MONTH);
if (cycleDayOfMonth < MIN_DAY) {
cycleDayOfMonth = MIN_DAY;
}
if (cycleDayOfMonth > MAX_DAY) {
cycleDayOfMonth = MAX_DAY;
}
mCycleDayOfMonthPicker = view.findViewById(R.id.cycle_reset_day_of_month);
mCycleDayOfMonthPicker.setMinValue(MIN_DAY);
mCycleDayOfMonthPicker.setMaxValue(MAX_DAY);
mCycleDayOfMonthPicker.setValue(cycleDayOfMonth);
mCycleDayOfMonthPicker.setWrapSelectorWheel(true);
mUpArrow = view.findViewById(R.id.up_arrow_container);
mUpArrow.setOnTouchListener(new CycleArrowTouchListener(
() -> mCycleDayOfMonthPicker.setValue(mCycleDayOfMonthPicker.getValue() - 1),
TIME_INTERVAL_MILLIS));
mDownArrow = view.findViewById(R.id.down_arrow_container);
mDownArrow.setOnTouchListener(new CycleArrowTouchListener(
() -> mCycleDayOfMonthPicker.setValue(mCycleDayOfMonthPicker.getValue() + 1),
TIME_INTERVAL_MILLIS));
return builder
.setTitle(R.string.cycle_reset_day_of_month_picker_title)
.setView(view)
.setPositiveButton(R.string.cycle_reset_day_of_month_picker_positive_button,
(dialog, which) -> {
if (which == DialogInterface.BUTTON_POSITIVE) {
if (mResetDayOfMonthPickedListener != null) {
mResetDayOfMonthPickedListener.onDayOfMonthPicked(
mCycleDayOfMonthPicker.getValue());
}
}
})
.create();
}
/** Gets the current day of month selected by the {@link NumberPicker}. */
public int getSelectedDayOfMonth() {
return mCycleDayOfMonthPicker.getValue();
}
/** A listener that is called when a date is selected. */
public interface ResetDayOfMonthPickedListener {
/** A method that determines how to process the selected day of month. */
void onDayOfMonthPicked(int dayOfMonth);
}
private static class CycleArrowTouchListener implements View.OnTouchListener {
private final IntervalActionListener mIntervalActionListener;
private final long mTimeIntervalMillis;
private Handler mHandler = new Handler();
private Runnable mAction;
CycleArrowTouchListener(IntervalActionListener listener, long timeIntervalMillis) {
mIntervalActionListener = listener;
mTimeIntervalMillis = timeIntervalMillis;
mAction = () -> {
mHandler.postDelayed(this.mAction, mTimeIntervalMillis);
maybeTriggerAction();
};
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mHandler.removeCallbacks(mAction);
mHandler.postDelayed(mAction, mTimeIntervalMillis);
maybeTriggerAction();
v.setPressed(true);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mHandler.removeCallbacks(mAction);
v.setPressed(false);
return true;
}
return false;
}
private void maybeTriggerAction() {
if (mIntervalActionListener != null) {
mIntervalActionListener.takeAction();
}
}
/** Action that should be taken per time interval that the button is held. */
interface IntervalActionListener {
/** Defines the action to take at each time interval. */
void takeAction();
}
}
}