Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
DatePickerDialog that honors the locale set by the app
package com.gilbert.wat.widget;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Calendar;
import android.app.DatePickerDialog;
import android.content.Context;
import android.os.Build;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
import com.gilbert.wat.R;
/**
* This class is a version of DatePickerDialog that honors the locale set by the app instead of the locale of the system.
* According to the <a href="http://code.google.com/p/android/issues/detail?id=25107">bug report on Android framework</a>,
* The date picker is not using the String array of shortened month of the Context of the App[1].
* Instead it uses the System locale[2].
*
*
* [1]<code>context.getResources().getStringArray(R.array.short_months);</code>
* [2]<a href="http://www.grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/widget/DatePicker.java#482">
* <code> mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, DateUtils.LENGTH_MEDIUM);</code>
* </a>
*
* This class is licensed under <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</a>
*
* @author Wat Chun Pang Gilbert
*
*
*/
public class AppLocaleDatePickerDialog extends DatePickerDialog implements OnDateChangedListener {
private static final String TAG = AppLocaleDatePickerDialog.class.getSimpleName();
private static final String MONTH_LONG_FORMAT = "MMMMMM, yyyy";
protected DatePicker mDatePicker;
protected Calendar mCalendar;
private int mInitialYear;
private int mInitialMonth;
private int mInitialDay;
public AppLocaleDatePickerDialog(Context context, int theme,
OnDateSetListener callBack, int year, int monthOfYear,
int dayOfMonth) {
super(context, theme, callBack, year, monthOfYear, dayOfMonth);
pullDatePickerRefFromSuper();
initPicker(context);
mInitialYear = year;
mInitialMonth = monthOfYear;
mInitialDay = dayOfMonth;
mCalendar = Calendar.getInstance();
mDatePicker.init(mInitialYear, mInitialMonth, mInitialDay, this);
updateTitle(mInitialYear, mInitialMonth, mInitialDay);
}
public AppLocaleDatePickerDialog(Context context, OnDateSetListener callBack,
int year, int monthOfYear, int dayOfMonth) {
this(context, 0, callBack, year, monthOfYear, dayOfMonth);
}
/**
* Use reflection to use the Locale of the application for the month spinner.
*
* PS: DAMN DATEPICKER DOESN'T HONOR Locale.getDefault()
* <a href="http://code.google.com/p/android/issues/detail?id=25107">Bug Report</a>
* @param context
*/
public void initPicker(Context context) {
String monthPickerVarName;
String months[] = context.getResources().getStringArray(R.array.short_months);
if (Build.VERSION.SDK_INT >= 14) {
monthPickerVarName = "mMonthSpinner";
} else {
monthPickerVarName = "mMonthPicker";
}
try {
Field f[] = mDatePicker.getClass().getDeclaredFields();
for (Field field : f) {
if (field.getName().equals("mShortMonths")) {
field.setAccessible(true);
field.set(mDatePicker, months);
} else if (field.getName().equals(monthPickerVarName)) {
field.setAccessible(true);
Object o = field.get(mDatePicker);
if (Build.VERSION.SDK_INT >= 14) {
Method m = o.getClass().getDeclaredMethod("setDisplayedValues", String[].class);
m.setAccessible(true);
m.invoke(o, (Object)months);
} else {
Method m = o.getClass().getDeclaredMethod("setRange", int.class, int.class, String[].class);
m.setAccessible(true);
m.invoke(o, 1, 12, (Object)months);
}
}
}
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
try {
final Method updateSpinner = mDatePicker.getClass().getDeclaredMethod("updateSpinners");
updateSpinner.setAccessible(true);
updateSpinner.invoke(mDatePicker);
updateSpinner.setAccessible(false);
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
/**
* Create references of private variables named:
* <i>mDatePicker</i> &amp; <i>mCalendar</i>
* of the super class to this class.
*/
private void pullDatePickerRefFromSuper() {
Field superF[] = AppLocaleDatePickerDialog.class.getSuperclass().getDeclaredFields();
for(Field fi : superF) {
if(fi.getName().equals("mDatePicker")) {
fi.setAccessible(true);
try {
mDatePicker = (DatePicker)fi.get(this);
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
} else if (fi.getName().equals("mCalendar")) {
fi.setAccessible(true);
try {
mCalendar = (Calendar)fi.get(this);
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
}
public void onDateChanged(DatePicker view, int year, int month, int day) {
view.init(year, month, day, this);
updateTitle(year, month, day);
}
private void updateTitle(int year, int month, int day) {
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, month);
mCalendar.set(Calendar.DAY_OF_MONTH, day);
setTitle(getMonthLongFormat(this.getContext()).format(mCalendar.getTime()));
}
/**
* @return the monthLongFormat
*/
public static SimpleDateFormat getMonthLongFormat(Context context) {
if (sMonthLongFormat != null) {
return sMonthLongFormat;
} else {
String prefLocale = PreferenceManager.getDefaultSharedPreferences(context
.getApplicationContext()).getString(PreferenceKey.DISPLAY_LANGUAGE, "en");
Locale displayLocale = new Locale(prefLocale);
return sMonthLongFormat = new SimpleDateFormat(MONTH_LONG_FORMAT, displayLocale);
}
}
}
@MahmoudMabrok
Copy link

MahmoudMabrok commented Sep 21, 2020

sMonthLongFormat not resolved in code

@charlieaboumoussa
Copy link

charlieaboumoussa commented Jun 18, 2021

Please if you could add the missing variable

sMonthLongFormat not resolved in code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment