Merge "Adding text input mode to TimePicker."
This commit is contained in:
committed by
Android (Google) Code Review
commit
fbffd434df
@@ -50554,6 +50554,7 @@ package android.widget {
|
||||
method public void setIs24HourView(java.lang.Boolean);
|
||||
method public void setMinute(int);
|
||||
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
|
||||
method public boolean validateInput();
|
||||
}
|
||||
|
||||
public static abstract interface TimePicker.OnTimeChangedListener {
|
||||
|
||||
@@ -54325,6 +54325,7 @@ package android.widget {
|
||||
method public void setIs24HourView(java.lang.Boolean);
|
||||
method public void setMinute(int);
|
||||
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
|
||||
method public boolean validateInput();
|
||||
}
|
||||
|
||||
public static abstract interface TimePicker.OnTimeChangedListener {
|
||||
|
||||
@@ -50879,6 +50879,7 @@ package android.widget {
|
||||
method public void setIs24HourView(java.lang.Boolean);
|
||||
method public void setMinute(int);
|
||||
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
|
||||
method public boolean validateInput();
|
||||
field public static final int MODE_CLOCK = 2; // 0x2
|
||||
field public static final int MODE_SPINNER = 1; // 0x1
|
||||
}
|
||||
|
||||
@@ -144,15 +144,26 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
getButton(BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (mTimePicker.validateInput()) {
|
||||
if (mTimeSetListener != null) {
|
||||
mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
|
||||
mTimePicker.getCurrentMinute());
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
case BUTTON_POSITIVE:
|
||||
if (mTimeSetListener != null) {
|
||||
mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
|
||||
mTimePicker.getCurrentMinute());
|
||||
}
|
||||
break;
|
||||
case BUTTON_NEGATIVE:
|
||||
cancel();
|
||||
break;
|
||||
|
||||
249
core/java/android/widget/TextInputTimePickerView.java
Normal file
249
core/java/android/widget/TextInputTimePickerView.java
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.MathUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* View to show text input based time picker with hour and minute fields and an optional AM/PM
|
||||
* spinner.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TextInputTimePickerView extends RelativeLayout {
|
||||
public static final int HOURS = 0;
|
||||
public static final int MINUTES = 1;
|
||||
public static final int AMPM = 2;
|
||||
|
||||
private static final int AM = 0;
|
||||
private static final int PM = 1;
|
||||
|
||||
private final EditText mHourEditText;
|
||||
private final EditText mMinuteEditText;
|
||||
private final TextView mInputSeparatorView;
|
||||
private final Spinner mAmPmSpinner;
|
||||
private final TextView mErrorLabel;
|
||||
private final TextView mHourLabel;
|
||||
private final TextView mMinuteLabel;
|
||||
|
||||
private boolean mIs24Hour;
|
||||
private boolean mHourFormatStartsAtZero;
|
||||
private OnValueTypedListener mListener;
|
||||
|
||||
private boolean mErrorShowing;
|
||||
|
||||
interface OnValueTypedListener {
|
||||
void onValueChanged(int inputType, int newValue);
|
||||
}
|
||||
|
||||
public TextInputTimePickerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public TextInputTimePickerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
this(context, attrs, defStyle, 0);
|
||||
}
|
||||
|
||||
public TextInputTimePickerView(Context context, AttributeSet attrs, int defStyle,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyle, defStyleRes);
|
||||
|
||||
inflate(context, R.layout.time_picker_text_input_material, this);
|
||||
|
||||
mHourEditText = (EditText) findViewById(R.id.input_hour);
|
||||
mMinuteEditText = (EditText) findViewById(R.id.input_minute);
|
||||
mInputSeparatorView = (TextView) findViewById(R.id.input_separator);
|
||||
mErrorLabel = (TextView) findViewById(R.id.label_error);
|
||||
mHourLabel = (TextView) findViewById(R.id.label_hour);
|
||||
mMinuteLabel = (TextView) findViewById(R.id.label_minute);
|
||||
|
||||
mHourEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
parseAndSetHourInternal(editable.toString());
|
||||
}
|
||||
});
|
||||
|
||||
mMinuteEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
parseAndSetMinuteInternal(editable.toString());
|
||||
}
|
||||
});
|
||||
|
||||
mAmPmSpinner = (Spinner) findViewById(R.id.am_pm_spinner);
|
||||
final String[] amPmStrings = TimePicker.getAmPmStrings(context);
|
||||
ArrayAdapter<CharSequence> adapter =
|
||||
new ArrayAdapter<CharSequence>(context, R.layout.simple_spinner_dropdown_item);
|
||||
adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[0]));
|
||||
adapter.add(TimePickerClockDelegate.obtainVerbatim(amPmStrings[1]));
|
||||
mAmPmSpinner.setAdapter(adapter);
|
||||
mAmPmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int position,
|
||||
long id) {
|
||||
if (position == 0) {
|
||||
mListener.onValueChanged(AMPM, AM);
|
||||
} else {
|
||||
mListener.onValueChanged(AMPM, PM);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {}
|
||||
});
|
||||
}
|
||||
|
||||
void setListener(OnValueTypedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
void setHourFormat(int maxCharLength) {
|
||||
mHourEditText.setFilters(new InputFilter[] {
|
||||
new InputFilter.LengthFilter(maxCharLength)});
|
||||
mMinuteEditText.setFilters(new InputFilter[] {
|
||||
new InputFilter.LengthFilter(maxCharLength)});
|
||||
}
|
||||
|
||||
boolean validateInput() {
|
||||
final boolean inputValid = parseAndSetHourInternal(mHourEditText.getText().toString())
|
||||
&& parseAndSetMinuteInternal(mMinuteEditText.getText().toString());
|
||||
setError(!inputValid);
|
||||
return inputValid;
|
||||
}
|
||||
|
||||
void updateSeparator(String separatorText) {
|
||||
mInputSeparatorView.setText(separatorText);
|
||||
}
|
||||
|
||||
private void setError(boolean enabled) {
|
||||
mErrorShowing = enabled;
|
||||
|
||||
mErrorLabel.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||
mHourLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
|
||||
mMinuteLabel.setVisibility(enabled ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the display value and updates the text of the view.
|
||||
* <p>
|
||||
* This method should be called whenever the current value or display
|
||||
* properties (leading zeroes, max digits) change.
|
||||
*/
|
||||
void updateTextInputValues(int localizedHour, int minute, int amOrPm, boolean is24Hour,
|
||||
boolean hourFormatStartsAtZero) {
|
||||
final String format = "%d";
|
||||
|
||||
mIs24Hour = is24Hour;
|
||||
mHourFormatStartsAtZero = hourFormatStartsAtZero;
|
||||
|
||||
mAmPmSpinner.setVisibility(is24Hour ? View.INVISIBLE : View.VISIBLE);
|
||||
|
||||
mHourEditText.setText(String.format(format, localizedHour));
|
||||
mMinuteEditText.setText(String.format(format, minute));
|
||||
|
||||
if (amOrPm == AM) {
|
||||
mAmPmSpinner.setSelection(0);
|
||||
} else {
|
||||
mAmPmSpinner.setSelection(1);
|
||||
}
|
||||
|
||||
if (mErrorShowing) {
|
||||
validateInput();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parseAndSetHourInternal(String input) {
|
||||
try {
|
||||
final int hour = Integer.parseInt(input);
|
||||
if (!isValidLocalizedHour(hour)) {
|
||||
final int minHour = mHourFormatStartsAtZero ? 0 : 1;
|
||||
final int maxHour = mIs24Hour ? 23 : 11 + minHour;
|
||||
mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(
|
||||
MathUtils.constrain(hour, minHour, maxHour)));
|
||||
return false;
|
||||
}
|
||||
mListener.onValueChanged(HOURS, getHourOfDayFromLocalizedHour(hour));
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
// Do nothing since we cannot parse the input.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parseAndSetMinuteInternal(String input) {
|
||||
try {
|
||||
final int minutes = Integer.parseInt(input);
|
||||
if (minutes < 0 || minutes > 59) {
|
||||
mListener.onValueChanged(MINUTES, MathUtils.constrain(minutes, 0, 59));
|
||||
return false;
|
||||
}
|
||||
mListener.onValueChanged(MINUTES, minutes);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
// Do nothing since we cannot parse the input.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidLocalizedHour(int localizedHour) {
|
||||
final int minHour = mHourFormatStartsAtZero ? 0 : 1;
|
||||
final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
|
||||
return localizedHour >= minHour && localizedHour <= maxHour;
|
||||
}
|
||||
|
||||
private int getHourOfDayFromLocalizedHour(int localizedHour) {
|
||||
int hourOfDay = localizedHour;
|
||||
if (mIs24Hour) {
|
||||
if (!mHourFormatStartsAtZero && localizedHour == 24) {
|
||||
hourOfDay = 0;
|
||||
}
|
||||
} else {
|
||||
if (!mHourFormatStartsAtZero && localizedHour == 12) {
|
||||
hourOfDay = 0;
|
||||
}
|
||||
if (mAmPmSpinner.getSelectedItemPosition() == 1) {
|
||||
hourOfDay += 12;
|
||||
}
|
||||
}
|
||||
return hourOfDay;
|
||||
}
|
||||
}
|
||||
@@ -278,6 +278,16 @@ public class TimePicker extends FrameLayout {
|
||||
return mDelegate.getBaseline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether current input by the user is a valid time based on the locale. TimePicker
|
||||
* will show an error message to the user if the time is not valid.
|
||||
*
|
||||
* @return {@code true} if the input is valid, {@code false} otherwise
|
||||
*/
|
||||
public boolean validateInput() {
|
||||
return mDelegate.validateInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
@@ -341,6 +351,8 @@ public class TimePicker extends FrameLayout {
|
||||
void setIs24Hour(boolean is24Hour);
|
||||
boolean is24Hour();
|
||||
|
||||
boolean validateInput();
|
||||
|
||||
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
|
||||
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
package android.widget;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.icu.text.DecimalFormatSymbols;
|
||||
import android.os.Parcelable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.format.DateFormat;
|
||||
@@ -40,11 +42,14 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
import android.widget.RadialTimePickerView.OnValueSelectedListener;
|
||||
import android.widget.TextInputTimePickerView.OnValueTypedListener;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.widget.NumericTextView;
|
||||
import com.android.internal.widget.NumericTextView.OnValueChangedListener;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
@@ -58,6 +63,13 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
*/
|
||||
private static final long DELAY_COMMIT_MILLIS = 2000;
|
||||
|
||||
@IntDef({FROM_EXTERNAL_API, FROM_RADIAL_PICKER, FROM_INPUT_PICKER})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface ChangeSource {}
|
||||
private static final int FROM_EXTERNAL_API = 0;
|
||||
private static final int FROM_RADIAL_PICKER = 1;
|
||||
private static final int FROM_INPUT_PICKER = 2;
|
||||
|
||||
// Index used by RadialPickerLayout
|
||||
private static final int HOUR_INDEX = RadialTimePickerView.HOURS;
|
||||
private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES;
|
||||
@@ -78,6 +90,15 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
private final RadialTimePickerView mRadialTimePickerView;
|
||||
private final TextView mSeparatorView;
|
||||
|
||||
private boolean mRadialPickerModeEnabled = true;
|
||||
private final ImageButton mRadialTimePickerModeButton;
|
||||
private final String mRadialTimePickerModeEnabledDescription;
|
||||
private final String mTextInputPickerModeEnabledDescription;
|
||||
private final View mRadialTimePickerHeader;
|
||||
private final View mTextInputPickerHeader;
|
||||
|
||||
private final TextInputTimePickerView mTextInputPickerView;
|
||||
|
||||
private final Calendar mTempCalendar;
|
||||
|
||||
// Accessibility strings.
|
||||
@@ -116,8 +137,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
|
||||
R.layout.time_picker_material);
|
||||
final View mainView = inflater.inflate(layoutResourceId, delegator);
|
||||
final View headerView = mainView.findViewById(R.id.time_header);
|
||||
headerView.setOnTouchListener(new NearestTouchDelegate());
|
||||
mRadialTimePickerHeader = mainView.findViewById(R.id.time_header);
|
||||
mRadialTimePickerHeader.setOnTouchListener(new NearestTouchDelegate());
|
||||
|
||||
// Set up hour/minute labels.
|
||||
mHourView = (NumericTextView) mainView.findViewById(R.id.hours);
|
||||
@@ -170,6 +191,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
headerTextColor = a.getColorStateList(R.styleable.TimePicker_headerTextColor);
|
||||
}
|
||||
|
||||
mTextInputPickerHeader = mainView.findViewById(R.id.input_header);
|
||||
|
||||
if (headerTextColor != null) {
|
||||
mHourView.setTextColor(headerTextColor);
|
||||
mSeparatorView.setTextColor(headerTextColor);
|
||||
@@ -180,7 +203,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
|
||||
// Set up header background, if available.
|
||||
if (a.hasValueOrEmpty(R.styleable.TimePicker_headerBackground)) {
|
||||
headerView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
|
||||
mRadialTimePickerHeader.setBackground(a.getDrawable(
|
||||
R.styleable.TimePicker_headerBackground));
|
||||
mTextInputPickerHeader.setBackground(a.getDrawable(
|
||||
R.styleable.TimePicker_headerBackground));
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
@@ -189,6 +215,22 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes);
|
||||
mRadialTimePickerView.setOnValueSelectedListener(mOnValueSelectedListener);
|
||||
|
||||
mTextInputPickerView = (TextInputTimePickerView) mainView.findViewById(R.id.input_mode);
|
||||
mTextInputPickerView.setListener(mOnValueTypedListener);
|
||||
|
||||
mRadialTimePickerModeButton =
|
||||
(ImageButton) mainView.findViewById(R.id.toggle_mode);
|
||||
mRadialTimePickerModeButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
toggleRadialPickerMode();
|
||||
}
|
||||
});
|
||||
mRadialTimePickerModeEnabledDescription = context.getResources().getString(
|
||||
R.string.time_picker_radial_mode_description);
|
||||
mTextInputPickerModeEnabledDescription = context.getResources().getString(
|
||||
R.string.time_picker_text_input_mode_description);
|
||||
|
||||
mAllowAutoAdvance = true;
|
||||
|
||||
updateHourFormat();
|
||||
@@ -200,6 +242,34 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
initialize(currentHour, currentMinute, mIs24Hour, HOUR_INDEX);
|
||||
}
|
||||
|
||||
private void toggleRadialPickerMode() {
|
||||
if (mRadialPickerModeEnabled) {
|
||||
mRadialTimePickerView.setVisibility(View.GONE);
|
||||
mRadialTimePickerHeader.setVisibility(View.GONE);
|
||||
mTextInputPickerHeader.setVisibility(View.VISIBLE);
|
||||
mTextInputPickerView.setVisibility(View.VISIBLE);
|
||||
mRadialTimePickerModeButton.setImageResource(R.drawable.btn_event_material);
|
||||
mRadialTimePickerModeButton.setContentDescription(
|
||||
mRadialTimePickerModeEnabledDescription);
|
||||
mRadialPickerModeEnabled = false;
|
||||
} else {
|
||||
mRadialTimePickerView.setVisibility(View.VISIBLE);
|
||||
mRadialTimePickerHeader.setVisibility(View.VISIBLE);
|
||||
mTextInputPickerHeader.setVisibility(View.GONE);
|
||||
mTextInputPickerView.setVisibility(View.GONE);
|
||||
mRadialTimePickerModeButton.setImageResource(R.drawable.btn_keyboard_key_material);
|
||||
mRadialTimePickerModeButton.setContentDescription(
|
||||
mTextInputPickerModeEnabledDescription);
|
||||
updateTextInputPicker();
|
||||
mRadialPickerModeEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateInput() {
|
||||
return mTextInputPickerView.validateInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a TextView is wide enough to contain its text without
|
||||
* wrapping or clipping. Measures the specified view and sets the minimum
|
||||
@@ -249,9 +319,16 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
final int maxHour = (mIs24Hour ? 23 : 11) + minHour;
|
||||
mHourView.setRange(minHour, maxHour);
|
||||
mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero);
|
||||
|
||||
final String[] digits = DecimalFormatSymbols.getInstance(mLocale).getDigitStrings();
|
||||
int maxCharLength = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
maxCharLength = Math.max(maxCharLength, digits[i].length());
|
||||
}
|
||||
mTextInputPickerView.setHourFormat(maxCharLength * 2);
|
||||
}
|
||||
|
||||
private static final CharSequence obtainVerbatim(String text) {
|
||||
static final CharSequence obtainVerbatim(String text) {
|
||||
return new SpannableStringBuilder().append(text,
|
||||
new TtsSpan.VerbatimBuilder(text).build(), 0);
|
||||
}
|
||||
@@ -333,10 +410,16 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
updateHeaderSeparator();
|
||||
updateHeaderMinute(mCurrentMinute, false);
|
||||
updateRadialPicker(index);
|
||||
updateTextInputPicker();
|
||||
|
||||
mDelegator.invalidate();
|
||||
}
|
||||
|
||||
private void updateTextInputPicker() {
|
||||
mTextInputPickerView.updateTextInputValues(getLocalizedHour(mCurrentHour), mCurrentMinute,
|
||||
mCurrentHour < 12 ? AM : PM, mIs24Hour, mHourFormatStartsAtZero);
|
||||
}
|
||||
|
||||
private void updateRadialPicker(int index) {
|
||||
mRadialTimePickerView.initialize(mCurrentHour, mCurrentMinute, mIs24Hour);
|
||||
setCurrentItemShowing(index, false, true);
|
||||
@@ -381,10 +464,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
*/
|
||||
@Override
|
||||
public void setHour(int hour) {
|
||||
setHourInternal(hour, false, true);
|
||||
setHourInternal(hour, FROM_EXTERNAL_API, true);
|
||||
}
|
||||
|
||||
private void setHourInternal(int hour, boolean isFromPicker, boolean announce) {
|
||||
private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
|
||||
if (mCurrentHour == hour) {
|
||||
return;
|
||||
}
|
||||
@@ -393,10 +476,13 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
updateHeaderHour(hour, announce);
|
||||
updateHeaderAmPm();
|
||||
|
||||
if (!isFromPicker) {
|
||||
if (source != FROM_RADIAL_PICKER) {
|
||||
mRadialTimePickerView.setCurrentHour(hour);
|
||||
mRadialTimePickerView.setAmOrPm(hour < 12 ? AM : PM);
|
||||
}
|
||||
if (source != FROM_INPUT_PICKER) {
|
||||
updateTextInputPicker();
|
||||
}
|
||||
|
||||
mDelegator.invalidate();
|
||||
onTimeChanged();
|
||||
@@ -424,10 +510,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
*/
|
||||
@Override
|
||||
public void setMinute(int minute) {
|
||||
setMinuteInternal(minute, false);
|
||||
setMinuteInternal(minute, FROM_EXTERNAL_API);
|
||||
}
|
||||
|
||||
private void setMinuteInternal(int minute, boolean isFromPicker) {
|
||||
private void setMinuteInternal(int minute, @ChangeSource int source) {
|
||||
if (mCurrentMinute == minute) {
|
||||
return;
|
||||
}
|
||||
@@ -435,9 +521,12 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
mCurrentMinute = minute;
|
||||
updateHeaderMinute(minute, true);
|
||||
|
||||
if (!isFromPicker) {
|
||||
if (source != FROM_RADIAL_PICKER) {
|
||||
mRadialTimePickerView.setCurrentMinute(minute);
|
||||
}
|
||||
if (source != FROM_INPUT_PICKER) {
|
||||
updateTextInputPicker();
|
||||
}
|
||||
|
||||
mDelegator.invalidate();
|
||||
onTimeChanged();
|
||||
@@ -661,6 +750,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
|
||||
}
|
||||
mSeparatorView.setText(separatorText);
|
||||
mTextInputPickerView.updateSeparator(separatorText);
|
||||
}
|
||||
|
||||
static private int lastIndexOfAny(String str, char[] any) {
|
||||
@@ -712,7 +802,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
|
||||
if (mRadialTimePickerView.setAmOrPm(amOrPm)) {
|
||||
mCurrentHour = getHour();
|
||||
|
||||
updateTextInputPicker();
|
||||
if (mOnTimeChangedListener != null) {
|
||||
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
|
||||
}
|
||||
@@ -726,7 +816,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
switch (pickerType) {
|
||||
case RadialTimePickerView.HOURS:
|
||||
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
|
||||
setHourInternal(newValue, true, !isTransition);
|
||||
setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
|
||||
if (isTransition) {
|
||||
setCurrentItemShowing(MINUTE_INDEX, true, false);
|
||||
|
||||
@@ -735,7 +825,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
}
|
||||
break;
|
||||
case RadialTimePickerView.MINUTES:
|
||||
setMinuteInternal(newValue, true);
|
||||
setMinuteInternal(newValue, FROM_RADIAL_PICKER);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -745,6 +835,23 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
}
|
||||
};
|
||||
|
||||
private final OnValueTypedListener mOnValueTypedListener = new OnValueTypedListener() {
|
||||
@Override
|
||||
public void onValueChanged(int pickerType, int newValue) {
|
||||
switch (pickerType) {
|
||||
case TextInputTimePickerView.HOURS:
|
||||
setHourInternal(newValue, FROM_INPUT_PICKER, false);
|
||||
break;
|
||||
case TextInputTimePickerView.MINUTES:
|
||||
setMinuteInternal(newValue, FROM_INPUT_PICKER);
|
||||
break;
|
||||
case TextInputTimePickerView.AMPM:
|
||||
setAmOrPm(newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Listener for keyboard interaction. */
|
||||
private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() {
|
||||
@Override
|
||||
|
||||
@@ -219,6 +219,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void getHourFormatData() {
|
||||
final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mLocale,
|
||||
(mIs24HourView) ? "Hm" : "hm");
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Implementation of {@link android.widget.Space} that uses normal View drawing
|
||||
* rather than a no-op. Useful for dialogs and other places where the base View
|
||||
* class is too greedy when measured with AT_MOST.
|
||||
*/
|
||||
public final class DrawingSpace extends View {
|
||||
public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
public DrawingSpace(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public DrawingSpace(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public DrawingSpace(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare to: {@link View#getDefaultSize(int, int)}
|
||||
* <p>
|
||||
* If mode is AT_MOST, return the child size instead of the parent size
|
||||
* (unless it is too big).
|
||||
*/
|
||||
private static int getDefaultSizeNonGreedy(int size, int measureSpec) {
|
||||
int result = size;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
switch (specMode) {
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = size;
|
||||
break;
|
||||
case MeasureSpec.AT_MOST:
|
||||
result = Math.min(size, specSize);
|
||||
break;
|
||||
case MeasureSpec.EXACTLY:
|
||||
result = specSize;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(
|
||||
getDefaultSizeNonGreedy(getSuggestedMinimumWidth(), widthMeasureSpec),
|
||||
getDefaultSizeNonGreedy(getSuggestedMinimumHeight(), heightMeasureSpec));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The Android Open Source Project
|
||||
<!--
|
||||
Copyright (C) 2017 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.
|
||||
@@ -14,7 +15,15 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<item type="dimen" format="integer" name="time_picker_column_start_material">1</item>
|
||||
<item type="dimen" format="integer" name="time_picker_column_end_material">0</item>
|
||||
</resources>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#90ffffff"
|
||||
android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
|
||||
2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
|
||||
<path android:pathData="M0 0h24v24H0z" />
|
||||
</vector>
|
||||
32
core/res/res/drawable/btn_keyboard_key_material.xml
Normal file
32
core/res/res/drawable/btn_keyboard_key_material.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2017 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.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="#90ffffff"
|
||||
android:pathData="M20 5H4c-1.1 0-1.99 .9 -1.99 2L2 17c0 1.1 .9 2 2 2h16c1.1 0 2-.9
|
||||
2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0
|
||||
3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9
|
||||
7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z" />
|
||||
<path
|
||||
android:pathData="M0 0h24v24H0zm0 0h24v24H0z" />
|
||||
</vector>
|
||||
@@ -15,28 +15,17 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layoutDirection="ltr">
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- Provides a background for the time layout that extends into the button bar area. -->
|
||||
<com.android.internal.widget.DrawingSpace
|
||||
<LinearLayout
|
||||
android:id="@+id/time_header"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="@dimen/time_picker_column_start_material"
|
||||
android:layout_row="0"
|
||||
android:layout_rowSpan="3"
|
||||
android:layout_gravity="center|fill"
|
||||
android:layoutDirection="locale" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="@dimen/time_picker_column_start_material"
|
||||
android:layout_row="1"
|
||||
android:layout_gravity="center|fill"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding">
|
||||
|
||||
@@ -44,10 +33,8 @@
|
||||
android:id="@+id/time_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_centerInParent="true"
|
||||
android:paddingTop="@dimen/timepicker_radial_picker_top_margin"
|
||||
android:layout_marginBottom="-12dp">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- The hour should always be to the left of the separator,
|
||||
regardless of the current locale's layout direction. -->
|
||||
@@ -125,38 +112,71 @@
|
||||
android:includeFontPadding="false"
|
||||
android:button="@null" />
|
||||
</RadioGroup>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ViewStub
|
||||
android:id="@id/topPanel"
|
||||
android:layout="@layout/alert_dialog_title_material"
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/input_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:paddingStart="@dimen/dialog_padding_material"
|
||||
android:paddingEnd="@dimen/dialog_padding_material"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputHeader"
|
||||
android:text="@string/time_picker_header_text"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="@dimen/time_picker_column_end_material"
|
||||
android:layout_row="0"
|
||||
android:layout_gravity="top|fill_horizontal"
|
||||
android:layoutDirection="locale" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.widget.RadialTimePickerView
|
||||
android:id="@+id/radial_picker"
|
||||
android:layout_width="@dimen/timepicker_radial_picker_dimen"
|
||||
android:layout_height="@dimen/timepicker_radial_picker_dimen"
|
||||
android:layout_column="@dimen/time_picker_column_end_material"
|
||||
android:layout_row="1"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_gravity="center|fill"
|
||||
android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
|
||||
android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
|
||||
android:layoutDirection="locale" />
|
||||
<android.widget.RadialTimePickerView
|
||||
android:id="@+id/radial_picker"
|
||||
android:layout_width="@dimen/timepicker_radial_picker_dimen"
|
||||
android:layout_height="@dimen/timepicker_radial_picker_dimen"
|
||||
android:layout_gravity="center|fill"
|
||||
android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
|
||||
android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin"
|
||||
android:layoutDirection="locale" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@id/buttonPanel"
|
||||
android:layout="@layout/alert_dialog_button_bar_material"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="@dimen/time_picker_column_end_material"
|
||||
android:layout_row="2"
|
||||
android:layout_gravity="bottom|fill_horizontal"
|
||||
android:layoutDirection="locale" />
|
||||
</GridLayout>
|
||||
<android.widget.TextInputTimePickerView
|
||||
android:id="@+id/input_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageButton
|
||||
android:id="@+id/toggle_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:padding="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:src="@drawable/btn_keyboard_key_material"
|
||||
android:contentDescription="@string/time_picker_text_input_mode_description" />
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<ViewStub
|
||||
android:id="@id/buttonPanel"
|
||||
android:layout="@layout/alert_dialog_button_bar_material"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layoutDirection="locale" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -34,4 +34,53 @@
|
||||
android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
|
||||
android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
|
||||
android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/input_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="@dimen/dialog_padding_material"
|
||||
android:paddingEnd="@dimen/dialog_padding_material"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:includeFontPadding="false"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textSize="34sp"
|
||||
android:textColor="@color/white"
|
||||
android:text="@string/time_picker_header_text"/>
|
||||
<android.widget.TextInputTimePickerView
|
||||
android:id="@+id/input_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageButton
|
||||
android:id="@+id/toggle_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:padding="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:src="@drawable/btn_keyboard_key_material"
|
||||
android:contentDescription="@string/time_picker_text_input_mode_description" />
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<ViewStub
|
||||
android:id="@id/buttonPanel"
|
||||
android:layout="@layout/alert_dialog_button_bar_material"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layoutDirection="locale" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
90
core/res/res/layout/time_picker_text_input_material.xml
Normal file
90
core/res/res/layout/time_picker_text_input_material.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2017 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.
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/top_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="26dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/time_picker_prompt_label"
|
||||
android:textAppearance="@style/TextAppearance.Material.TimePicker.PromptLabel" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/input_block"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/top_label"
|
||||
android:layoutDirection="ltr">
|
||||
<EditText
|
||||
android:id="@+id/input_hour"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
|
||||
<TextView
|
||||
android:id="@+id/label_hour"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/input_hour"
|
||||
android:layout_alignStart="@id/input_hour"
|
||||
android:text="@string/time_picker_hour_label"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/input_separator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignEnd="@id/input_hour"
|
||||
android:layout_alignBaseline="@id/input_hour"
|
||||
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/input_minute"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@id/input_hour"
|
||||
android:layout_toEndOf="@id/input_separator"
|
||||
android:inputType="number"
|
||||
android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
|
||||
<TextView
|
||||
android:id="@+id/label_minute"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/input_minute"
|
||||
android:layout_alignStart="@id/input_minute"
|
||||
android:text="@string/time_picker_minute_label"/>
|
||||
|
||||
<TextView
|
||||
android:visibility="invisible"
|
||||
android:id="@+id/label_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/input_hour"
|
||||
android:layout_alignStart="@id/input_hour"
|
||||
android:textColor="?attr/textColorError"
|
||||
android:text="@string/time_picker_input_error" />
|
||||
</RelativeLayout>
|
||||
<Spinner
|
||||
android:id="@+id/am_pm_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@id/input_block"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
|
||||
</merge>
|
||||
@@ -475,9 +475,6 @@
|
||||
|
||||
<dimen name="chooser_grid_padding">0dp</dimen>
|
||||
|
||||
<item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
|
||||
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
|
||||
|
||||
<item type="dimen" name="aerr_padding_list_top">15dp</item>
|
||||
<item type="dimen" name="aerr_padding_list_bottom">8dp</item>
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
<dimen name="timepicker_radial_picker_dimen">296dp</dimen>
|
||||
<dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
|
||||
<dimen name="timepicker_radial_picker_horizontal_margin">16dp</dimen>
|
||||
<dimen name="timepicker_edit_text_size">24sp</dimen>
|
||||
|
||||
<!-- Used by RadialTimePicker in clock-style TimePicker. -->
|
||||
<dimen name="timepicker_selector_radius">20dp</dimen>
|
||||
|
||||
@@ -4471,4 +4471,20 @@
|
||||
<string name="device_storage_monitor_notification_channel">Device storage</string>
|
||||
<!-- Channel name for UsbDeviceManager adb debugging notifications -->
|
||||
<string name="adb_debugging_notification_channel_tv">USB debugging</string>
|
||||
|
||||
<!-- Label for the time picker hour input field. [CHAR LIMIT=20] -->
|
||||
<string name="time_picker_hour_label">hour</string>
|
||||
<!-- Label for the time picker minute input field. [CHAR LIMIT=20] -->
|
||||
<string name="time_picker_minute_label">minute</string>
|
||||
<!-- The title for the time picker dialog. [CHAR LIMIT=NONE] -->
|
||||
<string name="time_picker_header_text">Set time</string>
|
||||
<!-- Error shown to the user if they type in invalid hour or minute in the time picker. [CHAR LIMIT=NONE] -->
|
||||
<string name="time_picker_input_error">Enter a valid time</string>
|
||||
<!-- Label shown to the user in time picker to let them know that should type in time. [CHAR LIMIT=NONE] -->
|
||||
<string name="time_picker_prompt_label">Type in time</string>
|
||||
<!-- Accessibility string used for describing the button in time picker that changes the dialog to text input mode. [CHAR LIMIT=NONE] -->
|
||||
<string name="time_picker_text_input_mode_description">Switch to text input mode for the time input.</string>
|
||||
<!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] -->
|
||||
<string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -426,6 +426,21 @@ please see styles_device_defaults.xml.
|
||||
<item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Material.TimePicker.InputHeader" parent="TextAppearance.Material">
|
||||
<item name="textSize">@dimen/text_size_display_1_material</item>
|
||||
<item name="textColor">@color/white</item>
|
||||
<item name="fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Material.TimePicker.InputField" parent="TextAppearance.Material">
|
||||
<item name="textSize">@dimen/timepicker_edit_text_size</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Material.TimePicker.PromptLabel" parent="TextAppearance.Material">
|
||||
<item name="textSize">@dimen/timepicker_text_size_normal</item>
|
||||
<item name="fontFamily">sans-serif-medium</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
|
||||
<item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
|
||||
<item name="textSize">@dimen/date_picker_year_label_size</item>
|
||||
|
||||
@@ -2842,4 +2842,21 @@
|
||||
<!-- Accessibility fingerprint gestures -->
|
||||
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
|
||||
<java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
|
||||
|
||||
<!-- Time picker -->
|
||||
<java-symbol type="id" name="toggle_mode"/>
|
||||
<java-symbol type="id" name="input_mode"/>
|
||||
<java-symbol type="id" name="input_header"/>
|
||||
<java-symbol type="id" name="input_separator"/>
|
||||
<java-symbol type="id" name="input_hour"/>
|
||||
<java-symbol type="id" name="input_minute"/>
|
||||
<java-symbol type="id" name="am_pm_spinner"/>
|
||||
<java-symbol type="id" name="label_hour"/>
|
||||
<java-symbol type="id" name="label_minute"/>
|
||||
<java-symbol type="id" name="label_error"/>
|
||||
<java-symbol type="layout" name="time_picker_text_input_material"/>
|
||||
<java-symbol type="drawable" name="btn_keyboard_key_material"/>
|
||||
<java-symbol type="drawable" name="btn_event_material"/>
|
||||
<java-symbol type="string" name="time_picker_text_input_mode_description"/>
|
||||
<java-symbol type="string" name="time_picker_radial_mode_description"/>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user