package org.itsnat.droid.impl.xmlinflater.layout.attr.widget; import android.os.Build; import android.text.TextUtils; import android.view.View; import android.widget.CalendarView; 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.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_CalendarView_maxDate_minDate extends AttrDesc<ClassDescViewBased,View,AttrLayoutContext> { private static final String DEFAULT_MIN_DATE = "01/01/1900"; private static final String DEFAULT_MAX_DATE = "01/01/2100"; protected FieldContainer<Object> fieldDelegate; protected FieldContainer<Locale> fieldCurrentLocale; protected MethodContainer<Boolean> methodParseDate; protected FieldContainer<Calendar> fieldMaxMinDate; public AttrDescView_widget_CalendarView_maxDate_minDate(ClassDescViewBased parent, String name) { super(parent,name); Class calendarClassWithCurrentLocale,calendarClassWithParseDate,calendarClassWithMaxMinDate; if (Build.VERSION.SDK_INT < MiscUtil.LOLLIPOP) // < 21 { calendarClassWithCurrentLocale = parent.getDeclaredClass(); // CalendarView calendarClassWithParseDate = calendarClassWithCurrentLocale; calendarClassWithMaxMinDate = calendarClassWithCurrentLocale; } else // Lollipop y superiores { this.fieldDelegate = new FieldContainer<Object>(parent.getDeclaredClass(), "mDelegate"); calendarClassWithCurrentLocale = MiscUtil.resolveClass(CalendarView.class.getName() + "$AbstractCalendarViewDelegate"); if (Build.VERSION.SDK_INT == MiscUtil.LOLLIPOP) // 21 (5.0) { calendarClassWithParseDate = MiscUtil.resolveClass(CalendarView.class.getName() + "$LegacyCalendarViewDelegate"); calendarClassWithMaxMinDate = calendarClassWithParseDate; } else if (Build.VERSION.SDK_INT == MiscUtil.LOLLIPOP_MR1) // 22 (5.1) { // mDelegate puede ser un objeto android.widget.CalendarViewLegacyDelegate o android.widget.CalendarViewMaterialDelegate (ambas clases autónomas) dependiendo // de un MODE_HOLO o MODE_MATERIAL, NO SOPORTAMOS por ahora MODE_MATERIAL por lo que se creará un CalendarViewLegacyDelegate calendarClassWithParseDate = calendarClassWithCurrentLocale; // parseDate está ya en $AbstractCalendarViewDelegate calendarClassWithMaxMinDate = MiscUtil.resolveClass("android.widget.CalendarViewLegacyDelegate"); // CalendarViewLegacyDelegate no está ya embebida en CalendarView, es autónoma } else // 23 en adelante { calendarClassWithParseDate = parent.getDeclaredClass(); // CalendarView calendarClassWithMaxMinDate = MiscUtil.resolveClass("android.widget.CalendarViewLegacyDelegate"); // CalendarViewLegacyDelegate no está ya embebida en CalendarView, es autónoma } } this.fieldCurrentLocale = new FieldContainer<Locale>(calendarClassWithCurrentLocale, "mCurrentLocale"); this.methodParseDate = new MethodContainer<Boolean>(calendarClassWithParseDate,"parseDate",new Class[]{String.class,Calendar.class}); String fieldName = null; if ("maxDate".equals(name)) fieldName = "mMaxDate"; else if ("minDate".equals(name)) fieldName = "mMinDate"; this.fieldMaxMinDate = new FieldContainer<Calendar>(calendarClassWithMaxMinDate,fieldName); } @Override public void setAttribute(View view, DOMAttr attr, AttrLayoutContext attrCtx) { String date = getString(attr.getResourceDesc(),attrCtx.getXMLInflaterContext()); Object calendarObject = getCalendarObject((CalendarView)view); Locale currentLocale = fieldCurrentLocale.get(calendarObject); Calendar outDate = Calendar.getInstance(currentLocale); // No es necesario: outDate.clear(); if (!TextUtils.isEmpty(date)) { if (!parseDate(calendarObject,date, outDate)) // El código fuente de Android tolera un mal formato, nosotros no pues no hace más que complicarlo to_do throw new ItsNatDroidException("Date: " + date + " not in format: " + "MM/dd/yyyy"); } else // Caso de eliminación de atributo, interpretamos el "" como el deseo de poner los valores por defecto (más o menos es así en el código fuente) { String defaultMaxMin = null; if ("maxDate".equals(name)) defaultMaxMin = DEFAULT_MAX_DATE; else if ("minDate".equals(name)) defaultMaxMin = DEFAULT_MIN_DATE; parseDate(calendarObject,defaultMaxMin, outDate); } fieldMaxMinDate.set(calendarObject,outDate); } @Override public void removeAttribute(View view, AttrLayoutContext attrCtx) { String value = null; if ("maxDate".equals(name)) value = DEFAULT_MAX_DATE; else if ("minDate".equals(name)) value = DEFAULT_MIN_DATE; setAttributeToRemove(view, value,attrCtx); } private Object getCalendarObject(CalendarView view) { if (Build.VERSION.SDK_INT < MiscUtil.LOLLIPOP) return view; else return fieldDelegate.get(view); } private boolean parseDate(Object calendarObject,String date, Calendar outDate) { return methodParseDate.invoke(calendarObject,date,outDate); } }