package org.itsnat.droid.impl.xmlinflater.layout.attr.widget; import android.os.Build; import android.text.TextUtils; import android.view.View; import android.widget.DatePicker; import org.itsnat.droid.ItsNatDroidException; import org.itsnat.droid.impl.dom.DOMAttr; import org.itsnat.droid.impl.util.MiscUtil; import org.itsnat.droid.impl.xmlinflater.FieldContainer; import org.itsnat.droid.impl.xmlinflater.MethodContainer; import org.itsnat.droid.impl.xmlinflater.layout.AttrLayoutContext; import org.itsnat.droid.impl.xmlinflater.layout.PendingViewPostCreateProcess; import org.itsnat.droid.impl.xmlinflater.layout.classtree.ClassDescViewBased; import org.itsnat.droid.impl.xmlinflater.shared.attr.AttrDesc; import java.util.Calendar; import java.util.Locale; /** * Created by jmarranz on 30/04/14. */ public class AttrDescView_widget_DatePicker_maxDate_minDate extends AttrDesc<ClassDescViewBased,View,AttrLayoutContext> { private static final int DEFAULT_START_YEAR = 1900; private static final int DEFAULT_END_YEAR = 2100; protected FieldContainer<Object> fieldDelegate; protected FieldContainer<Locale> fieldCurrentLocale; protected MethodContainer<Boolean> methodParseDate; protected MethodContainer<Void> methodMaxMinDate; public AttrDescView_widget_DatePicker_maxDate_minDate(ClassDescViewBased parent, String name) { super(parent,name); Class datePickerClass1,datePickerClass2; if (Build.VERSION.SDK_INT < MiscUtil.LOLLIPOP) { datePickerClass1 = parent.getDeclaredClass(); datePickerClass2 = datePickerClass1; } else // Lollipop { this.fieldDelegate = new FieldContainer<Object>(parent.getDeclaredClass(), "mDelegate"); datePickerClass1 = MiscUtil.resolveClass(DatePicker.class.getName() + "$AbstractDatePickerDelegate"); datePickerClass2 = MiscUtil.resolveClass(DatePicker.class.getName() + "$DatePickerSpinnerDelegate"); } this.fieldCurrentLocale = new FieldContainer<Locale>(datePickerClass1, "mCurrentLocale"); this.methodParseDate = new MethodContainer<Boolean>(datePickerClass2,"parseDate",new Class[]{String.class,Calendar.class}); String methodName = null; if ("maxDate".equals(name)) methodName = "setMaxDate"; else if ("minDate".equals(name)) methodName = "setMinDate"; this.methodMaxMinDate = new MethodContainer<Void>(datePickerClass2,methodName,new Class[]{long.class}); } @Override public void setAttribute(final View view, DOMAttr attr, AttrLayoutContext attrCtx) { final String date = getString(attr.getResourceDesc(), attrCtx.getXMLInflaterContext()); final Object datePickerObject = getDatePickerObject((DatePicker) view); Runnable task = new Runnable() { @Override public void run() { // Delegamos al final porque los atributos maxDate y minDate tienen prioridad (ganan si están definidos) // sobre startYear y endYear Locale currentLocale = fieldCurrentLocale.get(datePickerObject); Calendar tempDate = Calendar.getInstance(currentLocale); tempDate.clear(); if (!TextUtils.isEmpty(date)) { if (!parseDate(datePickerObject,date, tempDate)) // El código fuente de Android tolera un mal formato, nosotros no pues no hace más que complicarlo t_odo throw new ItsNatDroidException("Date: " + date + " not in format: " + "MM/dd/yyyy"); } else { // Caso de eliminación de atributo, intrepretamos como el deseo de poner los valores por defecto (más o menos es así en el código fuente) // hay que tener en cuenta que es un valor explícito por lo que ignoramos/reemplazamos los posibles valores puestos // por los atributos endYear/startYear explícitamente if ("maxDate".equals(name)) tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER /*11*/, 31); else if ("minDate".equals(name)) tempDate.set(DEFAULT_START_YEAR,Calendar.JANUARY /*0*/, 1); } methodMaxMinDate.invoke(datePickerObject,tempDate.getTimeInMillis()); } }; PendingViewPostCreateProcess pendingViewPostCreateProcess = attrCtx.getPendingViewPostCreateProcess(); if (pendingViewPostCreateProcess != null) pendingViewPostCreateProcess.addPendingLayoutParamsTask(task); else task.run(); } @Override public void removeAttribute(View view, AttrLayoutContext attrCtx) { setAttributeToRemove(view, "", attrCtx); } private Object getDatePickerObject(DatePicker view) { if (Build.VERSION.SDK_INT < MiscUtil.LOLLIPOP) return view; else return fieldDelegate.get(view); } private boolean parseDate(Object datePickerObject,String date, Calendar outDate) { return methodParseDate.invoke(datePickerObject,date,outDate); } }