mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 730330 - Use android datetime-picker widget. r=wesj
--HG-- rename : mobile/android/base/widget/DatetimePicker.java => mobile/android/base/widget/DateTimePicker.java
This commit is contained in:
parent
b3ea25df6d
commit
11cf800ffe
@ -243,6 +243,12 @@ class GeckoInputConnection
|
||||
return super.setSelection(newSelection.start, newSelection.end);
|
||||
}
|
||||
|
||||
private static void postToUiThread(Runnable runnable) {
|
||||
// postToUiThread() is called by the Gecko and TimerTask threads.
|
||||
// The UI thread does not need to post Runnables to itself.
|
||||
GeckoApp.mAppContext.mMainHandler.post(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTextBeforeCursor(int length, int flags) {
|
||||
// Avoid underrunning text buffer.
|
||||
@ -991,16 +997,6 @@ class GeckoInputConnection
|
||||
}
|
||||
|
||||
public void notifyIME(int type, int state) {
|
||||
// For some input type we will use a widget to display the ui, for those we must not
|
||||
// display the ime. We can display a widget for date and time types and, if the sdk version
|
||||
// is greater than 11, for datetime/month/week as well.
|
||||
if (typeHint.equals("date") || typeHint.equals("time") ||
|
||||
(Build.VERSION.SDK_INT > 10 &&
|
||||
(typeHint.equals("datetime") || typeHint.equals("month") ||
|
||||
typeHint.equals("week") || typeHint.equals("datetime-local")))) {
|
||||
return;
|
||||
}
|
||||
|
||||
View v = getView();
|
||||
if (v == null)
|
||||
return;
|
||||
@ -1048,6 +1044,16 @@ class GeckoInputConnection
|
||||
}
|
||||
|
||||
public void notifyIMEEnabled(int state, String typeHint, final String modeHint, String actionHint) {
|
||||
// For some input type we will use a widget to display the ui, for those we must not
|
||||
// display the ime. We can display a widget for date and time types and, if the sdk version
|
||||
// is greater than 11, for datetime/month/week as well.
|
||||
if (typeHint.equals("date") || typeHint.equals("time") ||
|
||||
(Build.VERSION.SDK_INT > 10 &&
|
||||
(typeHint.equals("datetime") || typeHint.equals("month") ||
|
||||
typeHint.equals("week") || typeHint.equals("datetime-local")))) {
|
||||
return;
|
||||
}
|
||||
|
||||
View v = getView();
|
||||
|
||||
if (v == null)
|
||||
|
@ -166,6 +166,7 @@ FENNEC_JAVA_FILES = \
|
||||
ui/PanZoomTarget.java \
|
||||
ui/SimpleScaleGestureDetector.java \
|
||||
ui/SubdocumentScrollHelper.java \
|
||||
widget/DateTimePicker.java \
|
||||
GeckoNetworkManager.java \
|
||||
GeckoScreenOrientationListener.java \
|
||||
UpdateService.java \
|
||||
@ -329,6 +330,7 @@ RES_LAYOUT = \
|
||||
res/layout/awesomebar_tab_indicator.xml \
|
||||
res/layout/awesomebar_tabs.xml \
|
||||
res/layout/bookmark_edit.xml \
|
||||
res/layout/datetime_picker.xml \
|
||||
res/layout/doorhangerpopup.xml \
|
||||
res/layout/doorhanger.xml \
|
||||
res/layout/find_in_page_content.xml \
|
||||
|
@ -325,10 +325,10 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
||||
try {
|
||||
builder.setView(mInputs[0].getView());
|
||||
} catch(UnsupportedOperationException ex) {
|
||||
// We cannot display these input widgets with this sdk version,
|
||||
// do not display any dialog and finish the prompt now.
|
||||
finishDialog("{\"button\": -1}");
|
||||
return;
|
||||
// We cannot display these input widgets with this sdk version,
|
||||
// do not display any dialog and finish the prompt now.
|
||||
finishDialog("{\"button\": -1}");
|
||||
return;
|
||||
}
|
||||
} else if (length > 1) {
|
||||
LinearLayout linearLayout = new LinearLayout(GeckoApp.mAppContext);
|
||||
@ -339,21 +339,21 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
||||
linearLayout.addView(content);
|
||||
}
|
||||
} catch(UnsupportedOperationException ex) {
|
||||
// We cannot display these input widgets with this sdk version,
|
||||
// do not display any dialog and finish the prompt now.
|
||||
finishDialog("{\"button\": -1}");
|
||||
return;
|
||||
// We cannot display these input widgets with this sdk version,
|
||||
// do not display any dialog and finish the prompt now.
|
||||
finishDialog("{\"button\": -1}");
|
||||
return;
|
||||
}
|
||||
builder.setView((View)linearLayout);
|
||||
}
|
||||
|
||||
length = mButtons == null ? 0 : mButtons.length;
|
||||
if (length > 0) {
|
||||
builder.setPositiveButton(mButtons[0].label, this);
|
||||
builder.setPositiveButton(mButtons[0], this);
|
||||
if (length > 1) {
|
||||
builder.setNeutralButton(mButtons[1].label, this);
|
||||
builder.setNeutralButton(mButtons[1], this);
|
||||
if (length > 2) {
|
||||
builder.setNegativeButton(mButtons[2].label, this);
|
||||
builder.setNegativeButton(mButtons[2], this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -440,7 +440,7 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
||||
try {
|
||||
mPromptQueue.put(aReturn);
|
||||
} catch(Exception ex) {
|
||||
Log.d(LOGTAG, "mPromptQueue not ready yet");
|
||||
Log.d(LOGTAG, "mPromptQueue not ready yet");
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,11 +562,11 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
||||
private static final int VIEW_TYPE_COUNT = 2;
|
||||
|
||||
public ListView listView = null;
|
||||
private int mResourceId = -1;
|
||||
PromptListAdapter(Context context, int textViewResourceId, PromptListItem[] objects) {
|
||||
private int mResourceId = -1;
|
||||
PromptListAdapter(Context context, int textViewResourceId, PromptListItem[] objects) {
|
||||
super(context, textViewResourceId, objects);
|
||||
mResourceId = textViewResourceId;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
|
@ -171,6 +171,8 @@ size. -->
|
||||
<!ENTITY button_ok "OK">
|
||||
<!ENTITY button_cancel "Cancel">
|
||||
<!ENTITY button_clear_data "Clear data">
|
||||
<!ENTITY button_set "Set">
|
||||
<!ENTITY button_clear "Clear">
|
||||
|
||||
<!ENTITY abouthome_addons_title "Add-ons for your &brandShortName;">
|
||||
<!ENTITY abouthome_addons_browse "Browse all &brandShortName; add-ons">
|
||||
|
@ -22,65 +22,117 @@
|
||||
<!-- Warning: everything within the "pickers" layout is removed and re-ordered
|
||||
depending on the date format selected by the user.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/datetime_picker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<LinearLayout android:id="@+id/pickers"
|
||||
<LinearLayout android:id="@+id/spinners"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Month -->
|
||||
<NumberPicker
|
||||
android:id="@+id/month"
|
||||
<LinearLayout android:id="@+id/date_spinners"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Day -->
|
||||
<NumberPicker
|
||||
android:id="@+id/day"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
<!-- Month -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/month"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
<!-- Year -->
|
||||
<NumberPicker
|
||||
android:id="@+id/year"
|
||||
<!-- Week -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/week"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
<!-- Day -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/day"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
<!-- Year -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/year"
|
||||
android:layout_width="75dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:id="@+id/time_spinners"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Hour -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/hour"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/mincolon"
|
||||
android:text=":"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"/>
|
||||
|
||||
<!-- Minute -->
|
||||
<android.widget.NumberPicker
|
||||
android:id="@+id/minute"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="1dip"
|
||||
android:layout_marginRight="1dip"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- calendar view -->
|
||||
<CalendarView
|
||||
android:id="@+id/calendar_view"
|
||||
android:layout_width="245dip"
|
||||
android:layout_height="280dip"
|
||||
android:layout_marginLeft="44dip"
|
||||
android:layout_weight="1"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -164,6 +164,8 @@
|
||||
<string name="button_ok">&button_ok;</string>
|
||||
<string name="button_cancel">&button_cancel;</string>
|
||||
<string name="button_clear_data">&button_clear_data;</string>
|
||||
<string name="button_set">&button_set;</string>
|
||||
<string name="button_clear">&button_clear;</string>
|
||||
|
||||
<string name="abouthome_addons_title">&abouthome_addons_title;</string>
|
||||
<string name="abouthome_addons_browse">&abouthome_addons_browse;</string>
|
||||
|
610
mobile/android/base/widget/DateTimePicker.java
Normal file
610
mobile/android/base/widget/DateTimePicker.java
Normal file
@ -0,0 +1,610 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 org.mozilla.gecko.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.Display;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CalendarView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.FrameLayout.LayoutParams;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.TextView;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
|
||||
public class DateTimePicker extends FrameLayout {
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
private static final String LOGTAG = "GeckoDateTimePicker";
|
||||
private static final String DATE_FORMAT = "MM/dd/yyyy";
|
||||
private static final int DEFAULT_START_YEAR = 1;
|
||||
private static final int DEFAULT_END_YEAR = 9999;
|
||||
// Minimal screen width (in inches) for which we can show the calendar;
|
||||
private static final int SCREEN_SIZE_THRESHOLD = 5;
|
||||
private boolean mYearEnabled = true;
|
||||
private boolean mMonthEnabled = true;
|
||||
private boolean mWeekEnabled = false;
|
||||
private boolean mDayEnabled = true;
|
||||
private boolean mHourEnabled = true;
|
||||
private boolean mMinuteEnabled = true;
|
||||
private boolean mCalendarEnabled = false;
|
||||
// Size of the screen in inches;
|
||||
private int mScreenWidth;
|
||||
private int mScreenHeight;
|
||||
private OnValueChangeListener mOnChangeListener;
|
||||
private final LinearLayout mPickers;
|
||||
private final LinearLayout mDateSpinners;
|
||||
private final LinearLayout mTimeSpinners;
|
||||
private final LinearLayout mSpinners;
|
||||
private final NumberPicker mDaySpinner;
|
||||
private final NumberPicker mMonthSpinner;
|
||||
private final NumberPicker mWeekSpinner;
|
||||
private final NumberPicker mYearSpinner;
|
||||
private final NumberPicker mHourSpinner;
|
||||
private final NumberPicker mMinuteSpinner;
|
||||
private final CalendarView mCalendar;
|
||||
private final EditText mDaySpinnerInput;
|
||||
private final EditText mMonthSpinnerInput;
|
||||
private final EditText mWeekSpinnerInput;
|
||||
private final EditText mYearSpinnerInput;
|
||||
private final EditText mHourSpinnerInput;
|
||||
private final EditText mMinuteSpinnerInput;
|
||||
private Locale mCurrentLocale;
|
||||
private String[] mShortMonths;
|
||||
private int mNumberOfMonths;
|
||||
private Calendar mTempDate;
|
||||
private Calendar mMinDate;
|
||||
private Calendar mMaxDate;
|
||||
private Calendar mCurrentDate;
|
||||
private pickersState mState;
|
||||
|
||||
public static enum pickersState { DATE, MONTH, WEEK, TIME, DATETIME };
|
||||
|
||||
public class OnValueChangeListener implements NumberPicker.OnValueChangeListener {
|
||||
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
||||
updateInputState();
|
||||
mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
|
||||
boolean newBehavior = (Build.VERSION.SDK_INT > 10);
|
||||
if (newBehavior) {
|
||||
if (DEBUG) Log.d(LOGTAG, "Sdk version > 10, using new behavior");
|
||||
//The native date picker widget on these sdks increment
|
||||
//the next field when one field reach the maximum
|
||||
if (picker == mDaySpinner && mDayEnabled) {
|
||||
int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
int old = mTempDate.get(Calendar.DAY_OF_MONTH);
|
||||
setTempDate(Calendar.DAY_OF_MONTH, old, newVal, 1, maxDayOfMonth);
|
||||
} else if (picker == mMonthSpinner && mMonthEnabled) {
|
||||
int old = mTempDate.get(Calendar.MONTH);
|
||||
setTempDate(Calendar.MONTH, old, newVal, 0, 11);
|
||||
} else if (picker == mWeekSpinner) {
|
||||
int old = mTempDate.get(Calendar.WEEK_OF_YEAR);
|
||||
int maxWeekOfYear = mTempDate.getActualMaximum(Calendar.WEEK_OF_YEAR);
|
||||
setTempDate(Calendar.WEEK_OF_YEAR, old, newVal, 0, maxWeekOfYear);
|
||||
} else if (picker == mYearSpinner && mYearEnabled) {
|
||||
int month=mTempDate.get(Calendar.MONTH);
|
||||
mTempDate.set(Calendar.YEAR,newVal);
|
||||
// Changing the year shouldn't change the month. (in case of non-leap year a Feb 29)
|
||||
// change the day instead;
|
||||
if (month != mTempDate.get(Calendar.MONTH)){
|
||||
mTempDate.set(Calendar.MONTH, month);
|
||||
mTempDate.set(Calendar.DAY_OF_MONTH,
|
||||
mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
} else if (picker == mHourSpinner && mHourEnabled) {
|
||||
setTempDate(Calendar.HOUR_OF_DAY, oldVal, newVal, 0, 23);
|
||||
} else if (picker == mMinuteSpinner && mMinuteEnabled) {
|
||||
setTempDate(Calendar.MINUTE, oldVal, newVal, 0, 59);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) Log.d(LOGTAG,"Sdk version < 10, using old behavior");
|
||||
if (picker == mDaySpinner && mDayEnabled){
|
||||
mTempDate.set(Calendar.DAY_OF_MONTH, newVal);
|
||||
} else if (picker == mMonthSpinner && mMonthEnabled){
|
||||
mTempDate.set(Calendar.MONTH, newVal);
|
||||
if (mTempDate.get(Calendar.MONTH) == newVal+1){
|
||||
mTempDate.set(Calendar.MONTH, newVal);
|
||||
mTempDate.set(Calendar.DAY_OF_MONTH,
|
||||
mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
} else if (picker == mWeekSpinner){
|
||||
mTempDate.set(Calendar.WEEK_OF_YEAR, newVal);
|
||||
} else if (picker == mYearSpinner && mYearEnabled){
|
||||
int month=mTempDate.get(Calendar.MONTH);
|
||||
mTempDate.set(Calendar.YEAR, newVal);
|
||||
if (month != mTempDate.get(Calendar.MONTH)){
|
||||
mTempDate.set(Calendar.MONTH, month);
|
||||
mTempDate.set(Calendar.DAY_OF_MONTH,
|
||||
mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
} else if (picker == mHourSpinner && mHourEnabled){
|
||||
mTempDate.set(Calendar.HOUR_OF_DAY, newVal);
|
||||
} else if (picker == mMinuteSpinner && mMinuteEnabled){
|
||||
mTempDate.set(Calendar.MINUTE, newVal);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
setDate(mTempDate);
|
||||
if (mDayEnabled) {
|
||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
if(mWeekEnabled) {
|
||||
mWeekSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.WEEK_OF_YEAR));
|
||||
}
|
||||
updateCalendar();
|
||||
updateSpinners();
|
||||
notifyDateChanged();
|
||||
}
|
||||
|
||||
private void setTempDate(int field, int oldVal, int newVal, int min, int max) {
|
||||
if (oldVal == max && newVal == min ) {
|
||||
mTempDate.add(field, 1);
|
||||
} else if (oldVal == min && newVal == max) {
|
||||
mTempDate.add(field, -1);
|
||||
} else {
|
||||
mTempDate.add(field, newVal - oldVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
|
||||
final StringBuilder mBuilder = new StringBuilder();
|
||||
|
||||
final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US);
|
||||
|
||||
final Object[] mArgs = new Object[1];
|
||||
|
||||
public String format(int value) {
|
||||
mArgs[0] = value;
|
||||
mBuilder.delete(0, mBuilder.length());
|
||||
mFmt.format("%02d", mArgs);
|
||||
return mFmt.toString();
|
||||
}
|
||||
};
|
||||
|
||||
private void displayPickers() {
|
||||
setWeekShown(false);
|
||||
if (mState == pickersState.DATETIME) {
|
||||
return;
|
||||
}
|
||||
setHourShown(false);
|
||||
setMinuteShown(false);
|
||||
if (mState == pickersState.WEEK) {
|
||||
setDayShown(false);
|
||||
setMonthShown(false);
|
||||
setWeekShown(true);
|
||||
} else if (mState == pickersState.MONTH) {
|
||||
setDayShown(false);
|
||||
}
|
||||
}
|
||||
|
||||
public DateTimePicker(Context context) {
|
||||
this(context, "", "", pickersState.DATE);
|
||||
}
|
||||
|
||||
public DateTimePicker(Context context, String dateFormat, String dateTimeValue, pickersState state) {
|
||||
super(context);
|
||||
if (Build.VERSION.SDK_INT < 11) {
|
||||
throw new UnsupportedOperationException("Custom DateTimePicker is only available for SDK > 10");
|
||||
}
|
||||
setCurrentLocale(Locale.getDefault());
|
||||
mMinDate.set(DEFAULT_START_YEAR,1,1);
|
||||
mMaxDate.set(DEFAULT_END_YEAR,12,31);
|
||||
mState = state;
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
inflater.inflate(R.layout.datetime_picker, this, true);
|
||||
|
||||
mOnChangeListener = new OnValueChangeListener();
|
||||
|
||||
mDateSpinners = (LinearLayout)findViewById(R.id.date_spinners);
|
||||
mTimeSpinners = (LinearLayout)findViewById(R.id.time_spinners);
|
||||
mSpinners = (LinearLayout)findViewById(R.id.spinners);
|
||||
mPickers = (LinearLayout)findViewById(R.id.datetime_picker);
|
||||
|
||||
// We will display differently according to the screen size width.
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
display.getMetrics(dm);
|
||||
mScreenWidth = display.getWidth() / dm.densityDpi;
|
||||
mScreenHeight = display.getHeight() / dm.densityDpi;
|
||||
if (DEBUG) Log.d(LOGTAG, "screen width: " + mScreenWidth + " screen height: " + mScreenHeight);
|
||||
|
||||
// If we're displaying a date, the screen is wide enought (and if we're using a sdk where the calendar view exists)
|
||||
// then display a calendar.
|
||||
if ((mState == pickersState.DATE || mState == pickersState.DATETIME) &&
|
||||
Build.VERSION.SDK_INT > 10 && mScreenWidth >= SCREEN_SIZE_THRESHOLD) {
|
||||
if (DEBUG) Log.d(LOGTAG,"SDK > 10 and screen wide enough, displaying calendar");
|
||||
mCalendar = new CalendarView(context);
|
||||
mCalendar.setVisibility(GONE);
|
||||
|
||||
LayoutParams layoutParams = new LayoutParams(250,280);
|
||||
mCalendar.setLayoutParams(layoutParams);
|
||||
mCalendar.setFocusable(true);
|
||||
mCalendar.setFocusableInTouchMode(true);
|
||||
mCalendar.setMaxDate(mMaxDate.getTimeInMillis());
|
||||
mCalendar.setMinDate(mMinDate.getTimeInMillis());
|
||||
|
||||
mCalendar.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
|
||||
public void onSelectedDayChange(
|
||||
CalendarView view, int year, int month, int monthDay) {
|
||||
mTempDate.set(year, month, monthDay);
|
||||
setDate(mTempDate);
|
||||
notifyDateChanged();
|
||||
}
|
||||
});
|
||||
|
||||
mPickers.addView(mCalendar);
|
||||
} else {
|
||||
// If the screen is more wide than high, we are displaying daye and time spinners,
|
||||
// and if there is no calendar displayed,
|
||||
// we should display the fields in one row.
|
||||
if (mScreenWidth > mScreenHeight && mState == pickersState.DATETIME) {
|
||||
mSpinners.setOrientation(LinearLayout.HORIZONTAL);
|
||||
}
|
||||
mCalendar = null;
|
||||
}
|
||||
|
||||
// Find the initial date from the constructor arguments.
|
||||
try {
|
||||
if (!dateTimeValue.equals("")) {
|
||||
mTempDate.setTime(new SimpleDateFormat(dateFormat).parse(dateTimeValue));
|
||||
} else {
|
||||
mTempDate.setTimeInMillis(System.currentTimeMillis());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Error parsing format string: " + ex);
|
||||
mTempDate.setTimeInMillis(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
// Initialize all spinners.
|
||||
mDaySpinner = setupSpinner(R.id.day, 1,
|
||||
mTempDate.get(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setFormatter(TWO_DIGIT_FORMATTER);
|
||||
mDaySpinnerInput = (EditText) mDaySpinner.getChildAt(1);
|
||||
|
||||
mMonthSpinner = setupSpinner(R.id.month, 1,
|
||||
mTempDate.get(Calendar.MONTH));
|
||||
mMonthSpinner.setFormatter(TWO_DIGIT_FORMATTER);
|
||||
mMonthSpinner.setDisplayedValues(mShortMonths);
|
||||
mMonthSpinnerInput = (EditText) mMonthSpinner.getChildAt(1);
|
||||
|
||||
mWeekSpinner = setupSpinner(R.id.week, 1,
|
||||
mTempDate.get(Calendar.WEEK_OF_YEAR));
|
||||
mWeekSpinner.setFormatter(TWO_DIGIT_FORMATTER);
|
||||
mWeekSpinnerInput = (EditText) mWeekSpinner.getChildAt(1);
|
||||
|
||||
mYearSpinner = setupSpinner(R.id.year, DEFAULT_START_YEAR,
|
||||
DEFAULT_END_YEAR);
|
||||
mYearSpinnerInput = (EditText) mYearSpinner.getChildAt(1);
|
||||
|
||||
mHourSpinner = setupSpinner(R.id.hour, 0, 23);
|
||||
mHourSpinner.setFormatter(TWO_DIGIT_FORMATTER);
|
||||
mHourSpinnerInput = (EditText) mHourSpinner.getChildAt(1);
|
||||
|
||||
mMinuteSpinner = setupSpinner(R.id.minute, 0, 59);
|
||||
mMinuteSpinner.setFormatter(TWO_DIGIT_FORMATTER);
|
||||
mMinuteSpinnerInput = (EditText) mMinuteSpinner.getChildAt(1);
|
||||
|
||||
// The order in which the spinners are displayed are locale-dependent
|
||||
reorderDateSpinners();
|
||||
// Set the date to the initial date. Since this date can come from the user,
|
||||
// it can fire an exception (out-of-bound date)
|
||||
try {
|
||||
updateDate(mTempDate);
|
||||
} catch (Exception ex) { }
|
||||
|
||||
// Display only the pickers needed for the current state.
|
||||
displayPickers();
|
||||
}
|
||||
|
||||
public NumberPicker setupSpinner(int id, int min, int max) {
|
||||
NumberPicker mSpinner = (NumberPicker) findViewById(id);
|
||||
mSpinner.setMinValue(min);
|
||||
mSpinner.setMaxValue(max);
|
||||
mSpinner.setOnValueChangedListener(mOnChangeListener);
|
||||
mSpinner.setOnLongPressUpdateInterval(100);
|
||||
return mSpinner;
|
||||
}
|
||||
|
||||
public long getTimeInMillis(){
|
||||
return mCurrentDate.getTimeInMillis();
|
||||
}
|
||||
|
||||
private void reorderDateSpinners() {
|
||||
mDateSpinners.removeAllViews();
|
||||
char[] order = DateFormat.getDateFormatOrder(getContext());
|
||||
final int spinnerCount = order.length;
|
||||
for (int i = 0; i < spinnerCount; i++) {
|
||||
switch (order[i]) {
|
||||
case DateFormat.DATE:
|
||||
mDateSpinners.addView(mDaySpinner);
|
||||
break;
|
||||
case DateFormat.MONTH:
|
||||
mDateSpinners.addView(mMonthSpinner);
|
||||
break;
|
||||
case DateFormat.YEAR:
|
||||
mDateSpinners.addView(mYearSpinner);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
mDateSpinners.addView(mWeekSpinner);
|
||||
}
|
||||
|
||||
private void setDate(Calendar calendar){
|
||||
mCurrentDate = mTempDate;
|
||||
if (mCurrentDate.before(mMinDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||
} else if (mCurrentDate.after(mMaxDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInputState() {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager)
|
||||
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
if (mYearEnabled && inputMethodManager.isActive(mYearSpinnerInput)) {
|
||||
mYearSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (mMonthEnabled && inputMethodManager.isActive(mMonthSpinnerInput)) {
|
||||
mMonthSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (mDayEnabled && inputMethodManager.isActive(mDaySpinnerInput)) {
|
||||
mDaySpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (mHourEnabled && inputMethodManager.isActive(mHourSpinnerInput)) {
|
||||
mHourSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (mMinuteEnabled && inputMethodManager.isActive(mMinuteSpinnerInput)) {
|
||||
mMinuteSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSpinners() {
|
||||
if (mDayEnabled) {
|
||||
if (mCurrentDate.equals(mMinDate)) {
|
||||
mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
} else if (mCurrentDate.equals(mMaxDate)) {
|
||||
mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
} else {
|
||||
mDaySpinner.setMinValue(1);
|
||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
if (mWeekEnabled) {
|
||||
mWeekSpinner.setMinValue(1);
|
||||
mWeekSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.WEEK_OF_YEAR));
|
||||
mWeekSpinner.setValue(mCurrentDate.get(Calendar.WEEK_OF_YEAR));
|
||||
}
|
||||
|
||||
if (mMonthEnabled) {
|
||||
mMonthSpinner.setDisplayedValues(null);
|
||||
if (mCurrentDate.equals(mMinDate)) {
|
||||
mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
|
||||
mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
|
||||
} else if (mCurrentDate.equals(mMaxDate)) {
|
||||
mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
|
||||
mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
|
||||
} else {
|
||||
mMonthSpinner.setMinValue(0);
|
||||
mMonthSpinner.setMaxValue(11);
|
||||
}
|
||||
|
||||
String[] displayedValues = Arrays.copyOfRange(mShortMonths,
|
||||
mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
|
||||
mMonthSpinner.setDisplayedValues(displayedValues);
|
||||
mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
|
||||
}
|
||||
|
||||
if (mYearEnabled) {
|
||||
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
|
||||
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
|
||||
mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
|
||||
}
|
||||
|
||||
if (mHourEnabled) {
|
||||
mHourSpinner.setValue(mCurrentDate.get(Calendar.HOUR_OF_DAY));
|
||||
}
|
||||
if (mMinuteEnabled) {
|
||||
mMinuteSpinner.setValue(mCurrentDate.get(Calendar.MINUTE));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCalendar() {
|
||||
if (mCalendarEnabled){
|
||||
mCalendar.setDate(mCurrentDate.getTimeInMillis(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDateChanged() {
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
|
||||
}
|
||||
|
||||
public void toggleCalendar(boolean shown) {
|
||||
if ((mState != pickersState.DATE && mState != pickersState.DATETIME) ||
|
||||
Build.VERSION.SDK_INT < 11 || mScreenWidth < SCREEN_SIZE_THRESHOLD) {
|
||||
if (DEBUG) Log.d(LOGTAG,"Cannot display calendar on this device, in this state" +
|
||||
": screen width :"+mScreenWidth);
|
||||
return;
|
||||
}
|
||||
if (shown){
|
||||
mCalendarEnabled = true;
|
||||
mCalendar.setVisibility(VISIBLE);
|
||||
setYearShown(false);
|
||||
setWeekShown(false);
|
||||
setMonthShown(false);
|
||||
setDayShown(false);
|
||||
} else {
|
||||
mCalendar.setVisibility(GONE);
|
||||
setYearShown(true);
|
||||
setMonthShown(true);
|
||||
setDayShown(true);
|
||||
mSpinners.setOrientation(LinearLayout.HORIZONTAL);
|
||||
mCalendarEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setYearShown(boolean shown) {
|
||||
if (shown) {
|
||||
toggleCalendar(false);
|
||||
mYearSpinner.setVisibility(VISIBLE);
|
||||
mYearEnabled = true;
|
||||
} else {
|
||||
mYearSpinner.setVisibility(GONE);
|
||||
mYearEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setWeekShown(boolean shown) {
|
||||
if (shown) {
|
||||
toggleCalendar(false);
|
||||
mWeekSpinner.setVisibility(VISIBLE);
|
||||
mWeekEnabled = true;
|
||||
} else {
|
||||
mWeekSpinner.setVisibility(GONE);
|
||||
mWeekEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setMonthShown(boolean shown) {
|
||||
if (shown) {
|
||||
toggleCalendar(false);
|
||||
mMonthSpinner.setVisibility(VISIBLE);
|
||||
mMonthEnabled = true;
|
||||
} else {
|
||||
mMonthSpinner.setVisibility(GONE);
|
||||
mMonthEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDayShown(boolean shown) {
|
||||
if (shown) {
|
||||
toggleCalendar(false);
|
||||
mDaySpinner.setVisibility(VISIBLE);
|
||||
mDayEnabled = true;
|
||||
} else {
|
||||
mDaySpinner.setVisibility(GONE);
|
||||
mDayEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setHourShown(boolean shown) {
|
||||
if (shown) {
|
||||
mHourSpinner.setVisibility(VISIBLE);
|
||||
mHourEnabled= true;
|
||||
} else {
|
||||
mHourSpinner.setVisibility(GONE);
|
||||
mTimeSpinners.setVisibility(GONE);
|
||||
mHourEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setMinuteShown(boolean shown) {
|
||||
if (shown) {
|
||||
mMinuteSpinner.setVisibility(VISIBLE);
|
||||
mTimeSpinners.findViewById(R.id.mincolon).setVisibility(VISIBLE);
|
||||
mMinuteEnabled= true;
|
||||
} else {
|
||||
mMinuteSpinner.setVisibility(GONE);
|
||||
mTimeSpinners.findViewById(R.id.mincolon).setVisibility(GONE);
|
||||
mMinuteEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentLocale(Locale locale) {
|
||||
if (locale.equals(mCurrentLocale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentLocale = locale;
|
||||
|
||||
mTempDate = getCalendarForLocale(mTempDate, locale);
|
||||
mMinDate = getCalendarForLocale(mMinDate, locale);
|
||||
mMaxDate = getCalendarForLocale(mMaxDate, locale);
|
||||
mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
|
||||
|
||||
mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
|
||||
mShortMonths = new String[mNumberOfMonths];
|
||||
for (int i = 0; i < mNumberOfMonths; i++) {
|
||||
mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
|
||||
DateUtils.LENGTH_MEDIUM);
|
||||
}
|
||||
}
|
||||
|
||||
private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
|
||||
if (oldCalendar == null) {
|
||||
return Calendar.getInstance(locale);
|
||||
} else {
|
||||
final long currentTimeMillis = oldCalendar.getTimeInMillis();
|
||||
Calendar newCalendar = Calendar.getInstance(locale);
|
||||
newCalendar.setTimeInMillis(currentTimeMillis);
|
||||
return newCalendar;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDate(Calendar calendar) {
|
||||
if (mCurrentDate.equals(calendar)) {
|
||||
return;
|
||||
}
|
||||
mCurrentDate.setTimeInMillis(calendar.getTimeInMillis());
|
||||
if (mCurrentDate.before(mMinDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||
} else if (mCurrentDate.after(mMaxDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||
}
|
||||
updateSpinners();
|
||||
notifyDateChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,796 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.annotation.Widget;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.NumberPicker.OnValueChangeListener;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* This class is a widget for selecting a date. The date can be selected by a
|
||||
* year, month, and day spinners or a {@link CalendarView}. The set of spinners
|
||||
* and the calendar view are automatically synchronized. The client can
|
||||
* customize whether only the spinners, or only the calendar view, or both to be
|
||||
* displayed. Also the minimal and maximal date from which dates to be selected
|
||||
* can be customized.
|
||||
* <p>
|
||||
* See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date
|
||||
* Picker tutorial</a>.
|
||||
* </p>
|
||||
* <p>
|
||||
* For a dialog using this view, see {@link android.app.DatetimePickerDialog}.
|
||||
* </p>
|
||||
*
|
||||
* @attr ref android.R.styleable#DatetimePicker_startYear
|
||||
* @attr ref android.R.styleable#DatetimePicker_endYear
|
||||
* @attr ref android.R.styleable#DatetimePicker_maxDate
|
||||
* @attr ref android.R.styleable#DatetimePicker_minDate
|
||||
* @attr ref android.R.styleable#DatetimePicker_spinnersShown
|
||||
* @attr ref android.R.styleable#DatetimePicker_calendarViewShown
|
||||
*/
|
||||
@Widget
|
||||
public class DatetimePicker extends FrameLayout {
|
||||
|
||||
private static final String LOG_TAG = DatetimePicker.class.getSimpleName();
|
||||
|
||||
private static final String DATE_FORMAT = "MM/dd/yyyy";
|
||||
|
||||
private static final int DEFAULT_START_YEAR = 1900;
|
||||
|
||||
private static final int DEFAULT_END_YEAR = 2100;
|
||||
|
||||
private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
|
||||
|
||||
private static final boolean DEFAULT_SPINNERS_SHOWN = true;
|
||||
|
||||
private static final boolean DEFAULT_ENABLED_STATE = true;
|
||||
|
||||
private final LinearLayout mSpinners;
|
||||
|
||||
private final NumberPicker mDaySpinner;
|
||||
|
||||
private final NumberPicker mMonthSpinner;
|
||||
|
||||
private final NumberPicker mYearSpinner;
|
||||
|
||||
private final EditText mDaySpinnerInput;
|
||||
|
||||
private final EditText mMonthSpinnerInput;
|
||||
|
||||
private final EditText mYearSpinnerInput;
|
||||
|
||||
private final CalendarView mCalendarView;
|
||||
|
||||
private Locale mCurrentLocale;
|
||||
|
||||
private OnDateChangedListener mOnDateChangedListener;
|
||||
|
||||
private String[] mShortMonths;
|
||||
|
||||
private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
|
||||
|
||||
private int mNumberOfMonths;
|
||||
|
||||
private Calendar mTempDate;
|
||||
|
||||
private Calendar mMinDate;
|
||||
|
||||
private Calendar mMaxDate;
|
||||
|
||||
private Calendar mCurrentDate;
|
||||
|
||||
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
|
||||
|
||||
/**
|
||||
* The callback used to indicate the user changes\d the date.
|
||||
*/
|
||||
public interface OnDateChangedListener {
|
||||
|
||||
/**
|
||||
* Called upon a date change.
|
||||
*
|
||||
* @param view The view associated with this listener.
|
||||
* @param year The year that was set.
|
||||
* @param monthOfYear The month that was set (0-11) for compatibility
|
||||
* with {@link java.util.Calendar}.
|
||||
* @param dayOfMonth The day of the month that was set.
|
||||
*/
|
||||
void onDateChanged(DatetimePicker view, int year, int monthOfYear, int dayOfMonth);
|
||||
}
|
||||
|
||||
public DatetimePicker(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public DatetimePicker(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.datePickerStyle);
|
||||
}
|
||||
|
||||
public DatetimePicker(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
// initialization based on locale
|
||||
setCurrentLocale(Locale.getDefault());
|
||||
|
||||
TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatetimePicker,
|
||||
defStyle, 0);
|
||||
boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatetimePicker_spinnersShown,
|
||||
DEFAULT_SPINNERS_SHOWN);
|
||||
boolean calendarViewShown = attributesArray.getBoolean(
|
||||
R.styleable.DatetimePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
|
||||
int startYear = attributesArray.getInt(R.styleable.DatetimePicker_startYear,
|
||||
DEFAULT_START_YEAR);
|
||||
int endYear = attributesArray.getInt(R.styleable.DatetimePicker_endYear, DEFAULT_END_YEAR);
|
||||
String minDate = attributesArray.getString(R.styleable.DatetimePicker_minDate);
|
||||
String maxDate = attributesArray.getString(R.styleable.DatetimePicker_maxDate);
|
||||
int layoutResourceId = attributesArray.getResourceId(R.styleable.DatetimePicker_layout,
|
||||
R.layout.datetime_picker);
|
||||
attributesArray.recycle();
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(layoutResourceId, this, true);
|
||||
|
||||
OnValueChangeListener onChangeListener = new OnValueChangeListener() {
|
||||
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
|
||||
updateInputState();
|
||||
mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
|
||||
// take care of wrapping of days and months to update greater fields
|
||||
if (picker == mDaySpinner) {
|
||||
int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
if (oldVal == maxDayOfMonth && newVal == 1) {
|
||||
mTempDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
} else if (oldVal == 1 && newVal == maxDayOfMonth) {
|
||||
mTempDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||
} else {
|
||||
mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
|
||||
}
|
||||
} else if (picker == mMonthSpinner) {
|
||||
if (oldVal == 11 && newVal == 0) {
|
||||
mTempDate.add(Calendar.MONTH, 1);
|
||||
} else if (oldVal == 0 && newVal == 11) {
|
||||
mTempDate.add(Calendar.MONTH, -1);
|
||||
} else {
|
||||
mTempDate.add(Calendar.MONTH, newVal - oldVal);
|
||||
}
|
||||
} else if (picker == mYearSpinner) {
|
||||
mTempDate.set(Calendar.YEAR, newVal);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// now set the date to the adjusted one
|
||||
setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
|
||||
mTempDate.get(Calendar.DAY_OF_MONTH));
|
||||
updateSpinners();
|
||||
updateCalendarView();
|
||||
notifyDateChanged();
|
||||
}
|
||||
};
|
||||
|
||||
mSpinners = (LinearLayout) findViewById(R.id.pickers);
|
||||
|
||||
// calendar view day-picker
|
||||
mCalendarView = (CalendarView) findViewById(R.id.calendar_view);
|
||||
mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
|
||||
public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
|
||||
setDate(year, month, monthDay);
|
||||
updateSpinners();
|
||||
notifyDateChanged();
|
||||
}
|
||||
});
|
||||
|
||||
// day
|
||||
mDaySpinner = (NumberPicker) findViewById(R.id.day);
|
||||
mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
|
||||
mDaySpinner.setOnLongPressUpdateInterval(100);
|
||||
mDaySpinner.setOnValueChangedListener(onChangeListener);
|
||||
mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
|
||||
|
||||
// month
|
||||
mMonthSpinner = (NumberPicker) findViewById(R.id.month);
|
||||
mMonthSpinner.setMinValue(0);
|
||||
mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
|
||||
mMonthSpinner.setDisplayedValues(mShortMonths);
|
||||
mMonthSpinner.setOnLongPressUpdateInterval(200);
|
||||
mMonthSpinner.setOnValueChangedListener(onChangeListener);
|
||||
mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
|
||||
|
||||
// year
|
||||
mYearSpinner = (NumberPicker) findViewById(R.id.year);
|
||||
mYearSpinner.setOnLongPressUpdateInterval(100);
|
||||
mYearSpinner.setOnValueChangedListener(onChangeListener);
|
||||
mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
|
||||
|
||||
// show only what the user required but make sure we
|
||||
// show something and the spinners have higher priority
|
||||
if (!spinnersShown && !calendarViewShown) {
|
||||
setSpinnersShown(true);
|
||||
} else {
|
||||
setSpinnersShown(spinnersShown);
|
||||
setCalendarViewShown(calendarViewShown);
|
||||
}
|
||||
|
||||
// set the min date giving priority of the minDate over startYear
|
||||
mTempDate.clear();
|
||||
if (!TextUtils.isEmpty(minDate)) {
|
||||
if (!parseDate(minDate, mTempDate)) {
|
||||
mTempDate.set(startYear, 0, 1);
|
||||
}
|
||||
} else {
|
||||
mTempDate.set(startYear, 0, 1);
|
||||
}
|
||||
setMinDate(mTempDate.getTimeInMillis());
|
||||
|
||||
// set the max date giving priority of the maxDate over endYear
|
||||
mTempDate.clear();
|
||||
if (!TextUtils.isEmpty(maxDate)) {
|
||||
if (!parseDate(maxDate, mTempDate)) {
|
||||
mTempDate.set(endYear, 11, 31);
|
||||
}
|
||||
} else {
|
||||
mTempDate.set(endYear, 11, 31);
|
||||
}
|
||||
setMaxDate(mTempDate.getTimeInMillis());
|
||||
|
||||
// initialize to current date
|
||||
mCurrentDate.setTimeInMillis(System.currentTimeMillis());
|
||||
init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
|
||||
.get(Calendar.DAY_OF_MONTH), null);
|
||||
|
||||
// re-order the number spinners to match the current date format
|
||||
reorderSpinners();
|
||||
|
||||
// set content descriptions
|
||||
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
|
||||
setContentDescriptions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimal date supported by this {@link DatetimePicker} in
|
||||
* milliseconds since January 1, 1970 00:00:00 in
|
||||
* {@link TimeZone#getDefault()} time zone.
|
||||
* <p>
|
||||
* Note: The default minimal date is 01/01/1900.
|
||||
* <p>
|
||||
*
|
||||
* @return The minimal supported date.
|
||||
*/
|
||||
public long getMinDate() {
|
||||
return mCalendarView.getMinDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimal date supported by this {@link NumberPicker} in
|
||||
* milliseconds since January 1, 1970 00:00:00 in
|
||||
* {@link TimeZone#getDefault()} time zone.
|
||||
*
|
||||
* @param minDate The minimal supported date.
|
||||
*/
|
||||
public void setMinDate(long minDate) {
|
||||
mTempDate.setTimeInMillis(minDate);
|
||||
if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
|
||||
&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
|
||||
return;
|
||||
}
|
||||
mMinDate.setTimeInMillis(minDate);
|
||||
mCalendarView.setMinDate(minDate);
|
||||
if (mCurrentDate.before(mMinDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||
updateCalendarView();
|
||||
}
|
||||
updateSpinners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximal date supported by this {@link DatetimePicker} in
|
||||
* milliseconds since January 1, 1970 00:00:00 in
|
||||
* {@link TimeZone#getDefault()} time zone.
|
||||
* <p>
|
||||
* Note: The default maximal date is 12/31/2100.
|
||||
* <p>
|
||||
*
|
||||
* @return The maximal supported date.
|
||||
*/
|
||||
public long getMaxDate() {
|
||||
return mCalendarView.getMaxDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximal date supported by this {@link DatetimePicker} in
|
||||
* milliseconds since January 1, 1970 00:00:00 in
|
||||
* {@link TimeZone#getDefault()} time zone.
|
||||
*
|
||||
* @param maxDate The maximal supported date.
|
||||
*/
|
||||
public void setMaxDate(long maxDate) {
|
||||
mTempDate.setTimeInMillis(maxDate);
|
||||
if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
|
||||
&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
|
||||
return;
|
||||
}
|
||||
mMaxDate.setTimeInMillis(maxDate);
|
||||
mCalendarView.setMaxDate(maxDate);
|
||||
if (mCurrentDate.after(mMaxDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||
updateCalendarView();
|
||||
}
|
||||
updateSpinners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (mIsEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
super.setEnabled(enabled);
|
||||
mDaySpinner.setEnabled(enabled);
|
||||
mMonthSpinner.setEnabled(enabled);
|
||||
mYearSpinner.setEnabled(enabled);
|
||||
mCalendarView.setEnabled(enabled);
|
||||
mIsEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mIsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
onPopulateAccessibilityEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
super.onPopulateAccessibilityEvent(event);
|
||||
|
||||
final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
|
||||
String selectedDateUtterance = DateUtils.formatDateTime(mContext,
|
||||
mCurrentDate.getTimeInMillis(), flags);
|
||||
event.getText().add(selectedDateUtterance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
setCurrentLocale(newConfig.locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the {@link CalendarView} is shown.
|
||||
*
|
||||
* @return True if the calendar view is shown.
|
||||
* @see #getCalendarView()
|
||||
*/
|
||||
public boolean getCalendarViewShown() {
|
||||
return mCalendarView.isShown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link CalendarView}.
|
||||
*
|
||||
* @return The calendar view.
|
||||
* @see #getCalendarViewShown()
|
||||
*/
|
||||
public CalendarView getCalendarView () {
|
||||
return mCalendarView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the {@link CalendarView} is shown.
|
||||
*
|
||||
* @param shown True if the calendar view is to be shown.
|
||||
*/
|
||||
public void setCalendarViewShown(boolean shown) {
|
||||
mCalendarView.setVisibility(shown ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the spinners are shown.
|
||||
*
|
||||
* @return True if the spinners are shown.
|
||||
*/
|
||||
public boolean getSpinnersShown() {
|
||||
return mSpinners.isShown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the spinners are shown.
|
||||
*
|
||||
* @param shown True if the spinners are to be shown.
|
||||
*/
|
||||
public void setSpinnersShown(boolean shown) {
|
||||
mSpinners.setVisibility(shown ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current locale.
|
||||
*
|
||||
* @param locale The current locale.
|
||||
*/
|
||||
private void setCurrentLocale(Locale locale) {
|
||||
if (locale.equals(mCurrentLocale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentLocale = locale;
|
||||
|
||||
mTempDate = getCalendarForLocale(mTempDate, locale);
|
||||
mMinDate = getCalendarForLocale(mMinDate, locale);
|
||||
mMaxDate = getCalendarForLocale(mMaxDate, locale);
|
||||
mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
|
||||
|
||||
mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
|
||||
mShortMonths = new String[mNumberOfMonths];
|
||||
for (int i = 0; i < mNumberOfMonths; i++) {
|
||||
mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
|
||||
DateUtils.LENGTH_MEDIUM);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a calendar for locale bootstrapped with the value of a given calendar.
|
||||
*
|
||||
* @param oldCalendar The old calendar.
|
||||
* @param locale The locale.
|
||||
*/
|
||||
private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
|
||||
if (oldCalendar == null) {
|
||||
return Calendar.getInstance(locale);
|
||||
} else {
|
||||
final long currentTimeMillis = oldCalendar.getTimeInMillis();
|
||||
Calendar newCalendar = Calendar.getInstance(locale);
|
||||
newCalendar.setTimeInMillis(currentTimeMillis);
|
||||
return newCalendar;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders the spinners according to the date format that is
|
||||
* explicitly set by the user and if no such is set fall back
|
||||
* to the current locale's default format.
|
||||
*/
|
||||
private void reorderSpinners() {
|
||||
mSpinners.removeAllViews();
|
||||
char[] order = DateFormat.getDateFormatOrder(getContext());
|
||||
final int spinnerCount = order.length;
|
||||
for (int i = 0; i < spinnerCount; i++) {
|
||||
switch (order[i]) {
|
||||
case DateFormat.DATE:
|
||||
mSpinners.addView(mDaySpinner);
|
||||
setImeOptions(mDaySpinner, spinnerCount, i);
|
||||
break;
|
||||
case DateFormat.MONTH:
|
||||
mSpinners.addView(mMonthSpinner);
|
||||
setImeOptions(mMonthSpinner, spinnerCount, i);
|
||||
break;
|
||||
case DateFormat.YEAR:
|
||||
mSpinners.addView(mYearSpinner);
|
||||
setImeOptions(mYearSpinner, spinnerCount, i);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current date.
|
||||
*
|
||||
* @param year The year.
|
||||
* @param month The month which is <strong>starting from zero</strong>.
|
||||
* @param dayOfMonth The day of the month.
|
||||
*/
|
||||
public void updateDate(int year, int month, int dayOfMonth) {
|
||||
if (!isNewDate(year, month, dayOfMonth)) {
|
||||
return;
|
||||
}
|
||||
setDate(year, month, dayOfMonth);
|
||||
updateSpinners();
|
||||
updateCalendarView();
|
||||
notifyDateChanged();
|
||||
}
|
||||
|
||||
// Override so we are in complete control of save / restore for this widget.
|
||||
@Override
|
||||
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
|
||||
dispatchThawSelfOnly(container);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
setDate(ss.mYear, ss.mMonth, ss.mDay);
|
||||
updateSpinners();
|
||||
updateCalendarView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the state. If the provided values designate an inconsistent
|
||||
* date the values are normalized before updating the spinners.
|
||||
*
|
||||
* @param year The initial year.
|
||||
* @param monthOfYear The initial month <strong>starting from zero</strong>.
|
||||
* @param dayOfMonth The initial day of the month.
|
||||
* @param onDateChangedListener How user is notified date is changed by
|
||||
* user, can be null.
|
||||
*/
|
||||
public void init(int year, int monthOfYear, int dayOfMonth,
|
||||
OnDateChangedListener onDateChangedListener) {
|
||||
setDate(year, monthOfYear, dayOfMonth);
|
||||
updateSpinners();
|
||||
updateCalendarView();
|
||||
mOnDateChangedListener = onDateChangedListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given <code>date</code> and in case of success sets the result
|
||||
* to the <code>outDate</code>.
|
||||
*
|
||||
* @return True if the date was parsed.
|
||||
*/
|
||||
private boolean parseDate(String date, Calendar outDate) {
|
||||
try {
|
||||
outDate.setTime(mDateFormat.parse(date));
|
||||
return true;
|
||||
} catch (ParseException e) {
|
||||
Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNewDate(int year, int month, int dayOfMonth) {
|
||||
return (mCurrentDate.get(Calendar.YEAR) != year
|
||||
|| mCurrentDate.get(Calendar.MONTH) != dayOfMonth
|
||||
|| mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
|
||||
}
|
||||
|
||||
private void setDate(int year, int month, int dayOfMonth) {
|
||||
mCurrentDate.set(year, month, dayOfMonth);
|
||||
if (mCurrentDate.before(mMinDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
|
||||
} else if (mCurrentDate.after(mMaxDate)) {
|
||||
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSpinners() {
|
||||
// set the spinner ranges respecting the min and max dates
|
||||
if (mCurrentDate.equals(mMinDate)) {
|
||||
mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setWrapSelectorWheel(false);
|
||||
mMonthSpinner.setDisplayedValues(null);
|
||||
mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
|
||||
mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
|
||||
mMonthSpinner.setWrapSelectorWheel(false);
|
||||
} else if (mCurrentDate.equals(mMaxDate)) {
|
||||
mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setWrapSelectorWheel(false);
|
||||
mMonthSpinner.setDisplayedValues(null);
|
||||
mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
|
||||
mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
|
||||
mMonthSpinner.setWrapSelectorWheel(false);
|
||||
} else {
|
||||
mDaySpinner.setMinValue(1);
|
||||
mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
mDaySpinner.setWrapSelectorWheel(true);
|
||||
mMonthSpinner.setDisplayedValues(null);
|
||||
mMonthSpinner.setMinValue(0);
|
||||
mMonthSpinner.setMaxValue(11);
|
||||
mMonthSpinner.setWrapSelectorWheel(true);
|
||||
}
|
||||
|
||||
// make sure the month names are a zero based array
|
||||
// with the months in the month spinner
|
||||
String[] displayedValues = Arrays.copyOfRange(mShortMonths,
|
||||
mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
|
||||
mMonthSpinner.setDisplayedValues(displayedValues);
|
||||
|
||||
// year spinner range does not change based on the current date
|
||||
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
|
||||
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
|
||||
mYearSpinner.setWrapSelectorWheel(false);
|
||||
|
||||
// set the spinner values
|
||||
mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
|
||||
mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
|
||||
mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the calendar view with the current date.
|
||||
*/
|
||||
private void updateCalendarView() {
|
||||
mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The selected year.
|
||||
*/
|
||||
public int getYear() {
|
||||
return mCurrentDate.get(Calendar.YEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The selected month.
|
||||
*/
|
||||
public int getMonth() {
|
||||
return mCurrentDate.get(Calendar.MONTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The selected day of month.
|
||||
*/
|
||||
public int getDayOfMonth() {
|
||||
return mCurrentDate.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the listener, if such, for a change in the selected date.
|
||||
*/
|
||||
private void notifyDateChanged() {
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
|
||||
if (mOnDateChangedListener != null) {
|
||||
mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the IME options for a spinner based on its ordering.
|
||||
*
|
||||
* @param spinner The spinner.
|
||||
* @param spinnerCount The total spinner count.
|
||||
* @param spinnerIndex The index of the given spinner.
|
||||
*/
|
||||
private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
|
||||
final int imeOptions;
|
||||
if (spinnerIndex < spinnerCount - 1) {
|
||||
imeOptions = EditorInfo.IME_ACTION_NEXT;
|
||||
} else {
|
||||
imeOptions = EditorInfo.IME_ACTION_DONE;
|
||||
}
|
||||
TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
|
||||
input.setImeOptions(imeOptions);
|
||||
}
|
||||
|
||||
private void setContentDescriptions() {
|
||||
// Day
|
||||
String text = mContext.getString(R.string.datetime_picker_increment_day_button);
|
||||
mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
|
||||
text = mContext.getString(R.string.datetime_picker_decrement_day_button);
|
||||
mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
|
||||
// Month
|
||||
text = mContext.getString(R.string.datetime_picker_increment_month_button);
|
||||
mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
|
||||
text = mContext.getString(R.string.datetime_picker_decrement_month_button);
|
||||
mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
|
||||
// Year
|
||||
text = mContext.getString(R.string.datetime_picker_increment_year_button);
|
||||
mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
|
||||
text = mContext.getString(R.string.datetime_picker_decrement_year_button);
|
||||
mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
|
||||
}
|
||||
|
||||
private void updateInputState() {
|
||||
// Make sure that if the user changes the value and the IME is active
|
||||
// for one of the inputs if this widget, the IME is closed. If the user
|
||||
// changed the value via the IME and there is a next input the IME will
|
||||
// be shown, otherwise the user chose another means of changing the
|
||||
// value and having the IME up makes no sense.
|
||||
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
|
||||
if (inputMethodManager != null) {
|
||||
if (inputMethodManager.isActive(mYearSpinnerInput)) {
|
||||
mYearSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
|
||||
mMonthSpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
} else if (inputMethodManager.isActive(mDaySpinnerInput)) {
|
||||
mDaySpinnerInput.clearFocus();
|
||||
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for managing state storing/restoring.
|
||||
*/
|
||||
private static class SavedState extends BaseSavedState {
|
||||
|
||||
private final int mYear;
|
||||
|
||||
private final int mMonth;
|
||||
|
||||
private final int mDay;
|
||||
|
||||
/**
|
||||
* Constructor called from {@link DatetimePicker#onSaveInstanceState()}
|
||||
*/
|
||||
private SavedState(Parcelable superState, int year, int month, int day) {
|
||||
super(superState);
|
||||
mYear = year;
|
||||
mMonth = month;
|
||||
mDay = day;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor called from {@link #CREATOR}
|
||||
*/
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
mYear = in.readInt();
|
||||
mMonth = in.readInt();
|
||||
mDay = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(mYear);
|
||||
dest.writeInt(mMonth);
|
||||
dest.writeInt(mDay);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
// suppress unused and hiding
|
||||
public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
|
||||
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ var InputWidgetHelper = {
|
||||
},
|
||||
|
||||
show: function(aElement) {
|
||||
let type = aElement.getAttribute('type');
|
||||
let msg = {
|
||||
type: "Prompt:Show",
|
||||
title: Strings.browser.GetStringFromName("inputWidgetHelper." + aElement.getAttribute('type')),
|
||||
@ -31,7 +32,7 @@ var InputWidgetHelper = {
|
||||
{ label: Strings.browser.GetStringFromName("inputWidgetHelper.cancel") }
|
||||
],
|
||||
inputs: [
|
||||
{ type: aElement.getAttribute('type'), value: aElement.value }
|
||||
{ type: type, value: aElement.value }
|
||||
]
|
||||
};
|
||||
|
||||
@ -50,8 +51,8 @@ var InputWidgetHelper = {
|
||||
}
|
||||
} else if (data.button == 0) {
|
||||
// Commit the new value.
|
||||
if (aElement.value != data[aElement.getAttribute('type')]) {
|
||||
aElement.value = data[aElement.getAttribute('type')];
|
||||
if (aElement.value != data[type]) {
|
||||
aElement.value = data[type];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
|
||||
[
|
||||
["HelperApps", "chrome://browser/content/HelperApps.js"],
|
||||
["SelectHelper", "chrome://browser/content/SelectHelper.js"],
|
||||
["InputWidgetHelper", "chrome://browser/content/InputWidgetHelper.js"],
|
||||
["AboutReader", "chrome://browser/content/aboutReader.js"],
|
||||
["WebAppRT", "chrome://browser/content/WebAppRT.js"],
|
||||
].forEach(function (aScript) {
|
||||
|
Loading…
Reference in New Issue
Block a user