package com.googlecode.android_scripting.facade.ui; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.json.JSONArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import python.button.FancyButton; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.text.InputType; import android.text.method.DigitsKeyListener; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TableLayout; import android.widget.TextView; import com.googlecode.android_scripting.Log; @SuppressLint({ "UseValueOf", "DefaultLocale" }) public class ViewInflater { private static XmlPullParserFactory mFactory; public static final String ANDROID = "http://schemas.android.com/apk/res/android"; public static final int BASESEQ = 0x7f0f0000; private int mNextSeq = BASESEQ; private final Map<String, Integer> mIdList = new HashMap<String, Integer>(); private final List<String> mErrors = new ArrayList<String>(); private Context mContext; private DisplayMetrics mMetrics; private static final Map<String, Integer> mInputTypes = new HashMap<String, Integer>(); public static final Map<String, String> mColorNames = new HashMap<String, String>(); public static final Map<String, Integer> mRelative = new HashMap<String, Integer>(); static { mColorNames.put("aliceblue", "#f0f8ff"); mColorNames.put("antiquewhite", "#faebd7"); mColorNames.put("aqua", "#00ffff"); mColorNames.put("aquamarine", "#7fffd4"); mColorNames.put("azure", "#f0ffff"); mColorNames.put("beige", "#f5f5dc"); mColorNames.put("bisque", "#ffe4c4"); mColorNames.put("black", "#000000"); mColorNames.put("blanchedalmond", "#ffebcd"); mColorNames.put("blue", "#0000ff"); mColorNames.put("blueviolet", "#8a2be2"); mColorNames.put("brown", "#a52a2a"); mColorNames.put("burlywood", "#deb887"); mColorNames.put("cadetblue", "#5f9ea0"); mColorNames.put("chartreuse", "#7fff00"); mColorNames.put("chocolate", "#d2691e"); mColorNames.put("coral", "#ff7f50"); mColorNames.put("cornflowerblue", "#6495ed"); mColorNames.put("cornsilk", "#fff8dc"); mColorNames.put("crimson", "#dc143c"); mColorNames.put("cyan", "#00ffff"); mColorNames.put("darkblue", "#00008b"); mColorNames.put("darkcyan", "#008b8b"); mColorNames.put("darkgoldenrod", "#b8860b"); mColorNames.put("darkgray", "#a9a9a9"); mColorNames.put("darkgrey", "#a9a9a9"); mColorNames.put("darkgreen", "#006400"); mColorNames.put("darkkhaki", "#bdb76b"); mColorNames.put("darkmagenta", "#8b008b"); mColorNames.put("darkolivegreen", "#556b2f"); mColorNames.put("darkorange", "#ff8c00"); mColorNames.put("darkorchid", "#9932cc"); mColorNames.put("darkred", "#8b0000"); mColorNames.put("darksalmon", "#e9967a"); mColorNames.put("darkseagreen", "#8fbc8f"); mColorNames.put("darkslateblue", "#483d8b"); mColorNames.put("darkslategray", "#2f4f4f"); mColorNames.put("darkslategrey", "#2f4f4f"); mColorNames.put("darkturquoise", "#00ced1"); mColorNames.put("darkviolet", "#9400d3"); mColorNames.put("deeppink", "#ff1493"); mColorNames.put("deepskyblue", "#00bfff"); mColorNames.put("dimgray", "#696969"); mColorNames.put("dimgrey", "#696969"); mColorNames.put("dodgerblue", "#1e90ff"); mColorNames.put("firebrick", "#b22222"); mColorNames.put("floralwhite", "#fffaf0"); mColorNames.put("forestgreen", "#228b22"); mColorNames.put("fuchsia", "#ff00ff"); mColorNames.put("gainsboro", "#dcdcdc"); mColorNames.put("ghostwhite", "#f8f8ff"); mColorNames.put("gold", "#ffd700"); mColorNames.put("goldenrod", "#daa520"); mColorNames.put("gray", "#808080"); mColorNames.put("grey", "#808080"); mColorNames.put("green", "#008000"); mColorNames.put("greenyellow", "#adff2f"); mColorNames.put("honeydew", "#f0fff0"); mColorNames.put("hotpink", "#ff69b4"); mColorNames.put("indianred ", "#cd5c5c"); mColorNames.put("indigo ", "#4b0082"); mColorNames.put("ivory", "#fffff0"); mColorNames.put("khaki", "#f0e68c"); mColorNames.put("lavender", "#e6e6fa"); mColorNames.put("lavenderblush", "#fff0f5"); mColorNames.put("lawngreen", "#7cfc00"); mColorNames.put("lemonchiffon", "#fffacd"); mColorNames.put("lightblue", "#add8e6"); mColorNames.put("lightcoral", "#f08080"); mColorNames.put("lightcyan", "#e0ffff"); mColorNames.put("lightgoldenrodyellow", "#fafad2"); mColorNames.put("lightgray", "#d3d3d3"); mColorNames.put("lightgrey", "#d3d3d3"); mColorNames.put("lightgreen", "#90ee90"); mColorNames.put("lightpink", "#ffb6c1"); mColorNames.put("lightsalmon", "#ffa07a"); mColorNames.put("lightseagreen", "#20b2aa"); mColorNames.put("lightskyblue", "#87cefa"); mColorNames.put("lightslategray", "#778899"); mColorNames.put("lightslategrey", "#778899"); mColorNames.put("lightsteelblue", "#b0c4de"); mColorNames.put("lightyellow", "#ffffe0"); mColorNames.put("lime", "#00ff00"); mColorNames.put("limegreen", "#32cd32"); mColorNames.put("linen", "#faf0e6"); mColorNames.put("magenta", "#ff00ff"); mColorNames.put("maroon", "#800000"); mColorNames.put("mediumaquamarine", "#66cdaa"); mColorNames.put("mediumblue", "#0000cd"); mColorNames.put("mediumorchid", "#ba55d3"); mColorNames.put("mediumpurple", "#9370d8"); mColorNames.put("mediumseagreen", "#3cb371"); mColorNames.put("mediumslateblue", "#7b68ee"); mColorNames.put("mediumspringgreen", "#00fa9a"); mColorNames.put("mediumturquoise", "#48d1cc"); mColorNames.put("mediumvioletred", "#c71585"); mColorNames.put("midnightblue", "#191970"); mColorNames.put("mintcream", "#f5fffa"); mColorNames.put("mistyrose", "#ffe4e1"); mColorNames.put("moccasin", "#ffe4b5"); mColorNames.put("navajowhite", "#ffdead"); mColorNames.put("navy", "#000080"); mColorNames.put("oldlace", "#fdf5e6"); mColorNames.put("olive", "#808000"); mColorNames.put("olivedrab", "#6b8e23"); mColorNames.put("orange", "#ffa500"); mColorNames.put("orangered", "#ff4500"); mColorNames.put("orchid", "#da70d6"); mColorNames.put("palegoldenrod", "#eee8aa"); mColorNames.put("palegreen", "#98fb98"); mColorNames.put("paleturquoise", "#afeeee"); mColorNames.put("palevioletred", "#d87093"); mColorNames.put("papayawhip", "#ffefd5"); mColorNames.put("peachpuff", "#ffdab9"); mColorNames.put("peru", "#cd853f"); mColorNames.put("pink", "#ffc0cb"); mColorNames.put("plum", "#dda0dd"); mColorNames.put("powderblue", "#b0e0e6"); mColorNames.put("purple", "#800080"); mColorNames.put("red", "#ff0000"); mColorNames.put("rosybrown", "#bc8f8f"); mColorNames.put("royalblue", "#4169e1"); mColorNames.put("saddlebrown", "#8b4513"); mColorNames.put("salmon", "#fa8072"); mColorNames.put("sandybrown", "#f4a460"); mColorNames.put("seagreen", "#2e8b57"); mColorNames.put("seashell", "#fff5ee"); mColorNames.put("sienna", "#a0522d"); mColorNames.put("silver", "#c0c0c0"); mColorNames.put("skyblue", "#87ceeb"); mColorNames.put("slateblue", "#6a5acd"); mColorNames.put("slategray", "#708090"); mColorNames.put("slategrey", "#708090"); mColorNames.put("snow", "#fffafa"); mColorNames.put("springgreen", "#00ff7f"); mColorNames.put("steelblue", "#4682b4"); mColorNames.put("tan", "#d2b48c"); mColorNames.put("teal", "#008080"); mColorNames.put("thistle", "#d8bfd8"); mColorNames.put("tomato", "#ff6347"); mColorNames.put("turquoise", "#40e0d0"); mColorNames.put("violet", "#ee82ee"); mColorNames.put("wheat", "#f5deb3"); mColorNames.put("white", "#ffffff"); mColorNames.put("whitesmoke", "#f5f5f5"); mColorNames.put("yellow", "#ffff00"); mColorNames.put("yellowgreen", "#9acd32"); mRelative.put("above", RelativeLayout.ABOVE); mRelative.put("alignBaseline", RelativeLayout.ALIGN_BASELINE); mRelative.put("alignBottom", RelativeLayout.ALIGN_BOTTOM); mRelative.put("alignLeft", RelativeLayout.ALIGN_LEFT); mRelative.put("alignParentBottom", RelativeLayout.ALIGN_PARENT_BOTTOM); mRelative.put("alignParentLeft", RelativeLayout.ALIGN_PARENT_LEFT); mRelative.put("alignParentRight", RelativeLayout.ALIGN_PARENT_RIGHT); mRelative.put("alignParentTop", RelativeLayout.ALIGN_PARENT_TOP); mRelative.put("alignRight", RelativeLayout.ALIGN_PARENT_RIGHT); mRelative.put("alignTop", RelativeLayout.ALIGN_TOP); // mRelative.put("alignWithParentIfMissing",RelativeLayout.); // No idea // what this translates // to. mRelative.put("below", RelativeLayout.BELOW); mRelative.put("centerHorizontal", RelativeLayout.CENTER_HORIZONTAL); mRelative.put("centerInParent", RelativeLayout.CENTER_IN_PARENT); mRelative.put("centerVertical", RelativeLayout.CENTER_VERTICAL); mRelative.put("toLeftOf", RelativeLayout.LEFT_OF); mRelative.put("toRightOf", RelativeLayout.RIGHT_OF); } public static XmlPullParserFactory getFactory() throws XmlPullParserException { if (mFactory == null) { mFactory = XmlPullParserFactory.newInstance(); mFactory.setNamespaceAware(true); } return mFactory; } public static XmlPullParser getXml() throws XmlPullParserException { return getFactory().newPullParser(); } public static XmlPullParser getXml(InputStream is) throws XmlPullParserException { XmlPullParser xml = getXml(); xml.setInput(is, null); return xml; } public static XmlPullParser getXml(Reader ir) throws XmlPullParserException { XmlPullParser xml = getXml(); xml.setInput(ir); return xml; } public View inflate(Activity context, XmlPullParser xml) throws XmlPullParserException, IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { int event; mContext = context; mErrors.clear(); mMetrics = new DisplayMetrics(); context.getWindowManager().getDefaultDisplay().getMetrics(mMetrics); do { event = xml.next(); if (event == XmlPullParser.END_DOCUMENT) { return null; } } while (event != XmlPullParser.START_TAG); View view = inflateView(context, xml, null); return view; } private void addln(Object msg) { Log.d(msg.toString()); } @SuppressWarnings("rawtypes") public void setClickListener(View v, android.view.View.OnClickListener listener, OnItemClickListener itemListener) { if (v.isClickable()) { if (v instanceof AdapterView) { try { ((AdapterView) v).setOnItemClickListener(itemListener); } catch (RuntimeException e) { // Ignore this, not all controls support OnItemClickListener } } try { v.setOnClickListener(listener); } catch (RuntimeException e) { // And not all controls support OnClickListener. } } if (v instanceof ViewGroup) { ViewGroup vg = (ViewGroup) v; for (int i = 0; i < vg.getChildCount(); i++) { setClickListener(vg.getChildAt(i), listener, itemListener); } } } private View inflateView(Context context, XmlPullParser xml, ViewGroup root) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, XmlPullParserException, IOException { View view = buildView(context, xml, root); if (view == null) { return view; } int event; while ((event = xml.next()) != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_TAG: if (view == null || view instanceof ViewGroup) { inflateView(context, xml, (ViewGroup) view); } else { skipTag(xml); // Not really a view, probably, skip it. } break; case XmlPullParser.END_TAG: return view; } } return view; } private void skipTag(XmlPullParser xml) throws XmlPullParserException, IOException { int depth = xml.getDepth(); int event; while ((event = xml.next()) != XmlPullParser.END_DOCUMENT) { if (event == XmlPullParser.END_TAG && xml.getDepth() <= depth) { break; } } } private View buildView(Context context, XmlPullParser xml, ViewGroup root) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { View view = viewClass(context, xml.getName()); if (view != null) { getLayoutParams(view, root); // Make quite sure every view has a // layout param. for (int i = 0; i < xml.getAttributeCount(); i++) { String name = xml.getName();// TextView String ns = xml.getAttributeNamespace(i); String prefix = xml.getAttributePrefix(i);// android String attr = xml.getAttributeName(i);// background if (ANDROID.equals(ns)) {// http://schemas.android.com/apk/res/android setProperty(view, root, name, attr, xml.getAttributeValue(i));// value: 1dip } else { if (prefix.equals("fancy")) {// 无图片样式的按钮 setFancyProperty(view, root, name, attr, xml.getAttributeValue(i));// value: 1dip } } } if (root != null) { root.addView(view); } } return view; } @SuppressWarnings("deprecation") private int getLayoutValue(String value) { if (value == null) { return 0; } if (value.equals("match_parent")) { return LayoutParams.FILL_PARENT; } if (value.equals("wrap_content")) { return LayoutParams.WRAP_CONTENT; } if (value.equals("fill_parent")) { return LayoutParams.FILL_PARENT; } return (int) getFontSize(value); } public float getFontSize(String value) { int i; float size; String unit = "px"; for (i = 0; i < value.length(); i++) { char c = value.charAt(i); if (!(Character.isDigit(c) || c == '.')) { break; } } size = Float.parseFloat(value.substring(0, i)); if (i < value.length()) { unit = value.substring(i).trim(); } if (unit.equals("px")) { return size; } if (unit.equals("sp")) { return mMetrics.scaledDensity * size; } if (unit.equals("dp") || unit.equals("dip")) { return mMetrics.density * size; } float inches = mMetrics.ydpi * size; if (unit.equals("in")) { return inches; } if (unit.equals("pt")) { return inches / 72; } if (unit.equals("mm")) { return (float) (inches / 2.54); } return 0; } private int calcId(String value) { if (value == null) { return 0; } if (value.startsWith("@+id/")) { return tryGetId(value.substring(5)); } if (value.startsWith("@id/")) { return tryGetId(value.substring(4)); } try { return Integer.parseInt(value); } catch (NumberFormatException e) { return 0; } } private int tryGetId(String value) { Integer id = mIdList.get(value); if (id == null) { id = new Integer(mNextSeq++); mIdList.put(value, id); } return id; } private LayoutParams getLayoutParams(View view, ViewGroup root) { LayoutParams result = view.getLayoutParams(); if (result == null) { result = createLayoutParams(root); view.setLayoutParams(result); } return result; } private LayoutParams createLayoutParams(ViewGroup root) { LayoutParams result = null; if (root != null) { try { String lookfor = root.getClass().getName() + "$LayoutParams"; addln(lookfor); Class<? extends LayoutParams> clazz = Class.forName(lookfor) .asSubclass(LayoutParams.class); if (clazz != null) { Constructor<? extends LayoutParams> ct = clazz .getConstructor(int.class, int.class); result = ct.newInstance(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } } catch (Exception e) { result = null; } } if (result == null) { result = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } return result; } public void setProperty(View view, String attr, String value) { try { setProperty(view, (ViewGroup) view.getParent(), "", attr, value); } catch (Exception e) { mErrors.add(e.toString()); } } private void setProperty(View view, ViewGroup root, String name, String attr, String value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { addln(attr + ":" + value); if (attr.startsWith("layout_")) { setLayoutProperty(view, root, attr, value); } else if (attr.equals("id")) { view.setId(calcId(value)); } else if (attr.equals("gravity")) { setInteger(view, attr, getInteger(Gravity.class, value)); } else if (attr.equals("width") || attr.equals("height")) { setInteger(view, attr, (int) getFontSize(value)); } else if (attr.equals("minHeight")) { view.setMinimumHeight((int) getFontSize(value)); } else if (attr.equals("minWidth")) { view.setMinimumWidth((int) getFontSize(value)); } else if (attr.equals("inputType")) { setInteger(view, attr, getInteger(InputType.class, value)); } else if (attr.equals("digits") && view instanceof TextView) { ((TextView) view).setKeyListener(DigitsKeyListener .getInstance(value)); } else if (attr.startsWith("nextFocus")) { setInteger(view, attr + "Id", calcId(value)); } else if (attr.equals("padding")) { int size = (int) getFontSize(value); view.setPadding(size, size, size, size); } else if (attr.equals("paddingLeft")) { int left = (int) getFontSize(value); view.setPadding(left, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); } else if (attr.equals("paddingTop")) { int top = (int) getFontSize(value); view.setPadding(view.getPaddingLeft(), top, view.getPaddingRight(), view.getPaddingBottom()); } else if (attr.equals("paddingRight")) { int right = (int) getFontSize(value); view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), right, view.getPaddingBottom()); } else if (attr.equals("paddingBottom")) { int bottom = (int) getFontSize(value); view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), bottom); } else if (attr.equals("stretchColumns")) { setStretchColumns(view, value); } else if (attr.equals("textSize")) { setFloat(view, attr, getFontSize(value)); } else if (attr.equals("textColor")) { setInteger(view, attr, getColor(value)); } else if (attr.equals("textHighlightColor")) { setInteger(view, "HighlightColor", getColor(value)); } else if (attr.equals("textColorHint")) { setInteger(view, "LinkTextColor", getColor(value)); } else if (attr.equals("textStyle")) { TextView textview = (TextView) view; int style = getInteger(Typeface.class, value); if (style == 0) { textview.setTypeface(Typeface.DEFAULT); } else { textview.setTypeface(textview.getTypeface(), style); } } else if (attr.equals("typeface")) { TextView textview = (TextView) view; Typeface typeface = textview.getTypeface(); int style = typeface == null ? 0 : typeface.getStyle(); textview.setTypeface(Typeface.create(value, style)); } else if (attr.equals("background")) { setBackground(view, name, value);// 修改这里增加name段判断属于神么控件 } else if (attr.equals("src")) { setImage(view, value); } else { setDynamicProperty(view, attr, value); } } private void setFancyProperty(View view, ViewGroup root, String name, String attr, String value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { // Log.i("setFancyProperty"); FancyButton button = (FancyButton) view;// 强制转换该控件 addln(attr + ":" + value); // 以下属性针对于自定义按钮 if (attr.equals("defaultColor")) { button.setBackgroundColor(getColor(value));// #FFFFFF } else if (attr.equals("text")) { button.setText(value); } else if (attr.equals("textColor")) { button.setTextColor(getColor(value));// #FFFFFF } else if (attr.equals("textFont")) { button.setCustomTextFont(value); } else if (attr.equals("iconFont")) { button.setCustomIconFont(value); } else if (attr.equals("textSize")) { button.setTextSize((int) getFontSize(value)); } else if (attr.equals("iconResource")) { button.setIconResource(getDrawable(value));// file:///xx.png } else if (attr.equals("fontIconResource")) { // R.string.icon_add if (value.startsWith("@string")) { button.setIconResource(mContext.getResources().getString( mContext.getResources().getIdentifier( value.replace("@string/", ""), "string", mContext.getPackageName()))); } else if (value.indexOf("&#") > -1) { button.setIconResource(value); } } else if (attr.equals("fontIconSize")) { button.setFontIconSize((int) getFontSize(value));// 10sp } else if (attr.equals("iconPosition")) { // R.id.left button.setIconPosition(mContext.getResources().getIdentifier(value, "id", mContext.getPackageName())); } else if (attr.equals("borderColor")) { button.setBorderColor(getColor(value)); // #FFFFFF } else if (attr.equals("borderWidth")) { button.setBorderWidth((int) getFontSize(value));// 1dp } else if (attr.equals("focusColor")) { button.setFocusBackgroundColor(getColor(value));// #9bd823 } else if (attr.equals("radius")) { button.setRadius((int) getFontSize(value));// 30dp } else { setDynamicProperty(view, attr, value); } } private void setStretchColumns(View view, String value) { TableLayout table = (TableLayout) view; String[] values = value.split(","); for (String column : values) { table.setColumnStretchable(Integer.parseInt(column), true); } } private void setLayoutProperty(View view, ViewGroup root, String attr, String value) { LayoutParams layout = getLayoutParams(view, root); String layoutAttr = attr.substring(7); if (layoutAttr.equals("width")) { layout.width = getLayoutValue(value); } else if (layoutAttr.equals("height")) { layout.height = getLayoutValue(value); } else if (layoutAttr.equals("gravity")) { setIntegerField(layout, "gravity", getInteger(Gravity.class, value)); } else { if (layoutAttr.startsWith("margin") && layout instanceof MarginLayoutParams) { int size = (int) getFontSize(value); MarginLayoutParams margins = (MarginLayoutParams) layout; if (layoutAttr.equals("marginBottom")) { margins.bottomMargin = size; } else if (layoutAttr.equals("marginTop")) { margins.topMargin = size; } else if (layoutAttr.equals("marginLeft")) { margins.leftMargin = size; } else if (layoutAttr.equals("marginRight")) { margins.rightMargin = size; } } else if (layout instanceof RelativeLayout.LayoutParams) { int anchor = calcId(value); if (anchor == 0) { anchor = getInteger(RelativeLayout.class, value); } int rule = mRelative.get(layoutAttr); ((RelativeLayout.LayoutParams) layout).addRule(rule, anchor); } else { setIntegerField(layout, layoutAttr, getInteger(layout.getClass(), value)); } } } @SuppressLint("NewApi") @SuppressWarnings("deprecation") private void setBackground(View view, String name, String value) { if (value.startsWith("#")) { view.setBackgroundColor(getColor(value)); } else if (value.startsWith("@")) { setInteger(view, "backgroundResource", getInteger(view, value)); } else { if (Build.VERSION.SDK_INT >= 16) { view.setBackground(getDrawable(value)); } else { view.setBackgroundDrawable(getDrawable(value)); } } } @SuppressWarnings("deprecation") private Drawable getDrawable(String value) { try { Uri uri = Uri.parse(value); if ("file".equals(uri.getScheme())) { BitmapDrawable bd = new BitmapDrawable(uri.getPath()); return bd; } } catch (Exception e) { mErrors.add("failed to load drawable " + value); } return null; } private void setImage(View view, String value) { if (value.startsWith("@")) { setInteger(view, "imageResource", getInteger(view, value)); } else { try { Uri uri = Uri.parse(value); if ("file".equals(uri.getScheme())) { Bitmap bm = BitmapFactory.decodeFile(uri.getPath()); Method method = view.getClass().getMethod("setImageBitmap", Bitmap.class); method.invoke(view, bm); } else { mErrors.add("Only 'file' currently supported for images"); } } catch (Exception e) { mErrors.add("failed to set image " + value); } } } private void setIntegerField(Object target, String fieldName, int value) { try { Field f = target.getClass().getField(fieldName); f.setInt(target, value); } catch (Exception e) { mErrors.add("set field)" + fieldName + " failed. " + e.toString()); } } /** Expand single digit color to 2 digits. */ private int expandColor(String colorValue) { return Integer.parseInt(colorValue + colorValue, 16); } public int getColor(String value) { int a = 0xff, r = 0, g = 0, b = 0; if (value.startsWith("#")) { try { value = value.substring(1); if (value.length() == 4) { a = expandColor(value.substring(0, 1)); value = value.substring(1); } if (value.length() == 3) { r = expandColor(value.substring(0, 1)); g = expandColor(value.substring(1, 2)); b = expandColor(value.substring(2, 3)); } else { if (value.length() == 8) { a = Integer.parseInt(value.substring(0, 2), 16); value = value.substring(2); } if (value.length() == 6) { r = Integer.parseInt(value.substring(0, 2), 16); g = Integer.parseInt(value.substring(2, 4), 16); b = Integer.parseInt(value.substring(4, 6), 16); } } long result = (a << 24) | (r << 16) | (g << 8) | b; return (int) result; } catch (Exception e) { } } else if (mColorNames.containsKey(value.toLowerCase())) { return getColor(mColorNames.get(value.toLowerCase())); } mErrors.add("Unknown color " + value); return 0; } private int getInputType(String value) { int result = 0; Integer v = getInputTypes().get(value); if (v == null) { mErrors.add("Unkown input type " + value); } else { result = v; } return result; } private void setInteger(View view, String attr, int value) { String name = "set" + PCase(attr); Method m; try { if ((m = tryMethod(view, name, Context.class, int.class)) != null) { m.invoke(view, mContext, value); } else if ((m = tryMethod(view, name, int.class)) != null) { m.invoke(view, value); } } catch (Exception e) { addln(name + ":" + value + ":" + e.toString()); } } private void setFloat(View view, String attr, float value) { String name = "set" + PCase(attr); Method m; try { if ((m = tryMethod(view, name, Context.class, float.class)) != null) { m.invoke(view, mContext, value); } else if ((m = tryMethod(view, name, float.class)) != null) { m.invoke(view, value); } } catch (Exception e) { addln(name + ":" + value + ":" + e.toString()); } } private void setDynamicProperty(View view, String attr, String value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { String name = "set" + PCase(attr); try { Method m = tryMethod(view, name, CharSequence.class); if (m != null) { m.invoke(view, value); } else if ((m = tryMethod(view, name, Context.class, int.class)) != null) { m.invoke(view, mContext, getInteger(view, value)); } else if ((m = tryMethod(view, name, int.class)) != null) { m.invoke(view, getInteger(view, value)); } else if ((m = tryMethod(view, name, float.class)) != null) { m.invoke(view, Float.parseFloat(value)); } else if ((m = tryMethod(view, name, boolean.class)) != null) { m.invoke(view, Boolean.parseBoolean(value)); } else if ((m = tryMethod(view, name, Object.class)) != null) { m.invoke(view, value); } else { mErrors.add(view.getClass().getSimpleName() + ":" + attr + " Property not found."); } } catch (Exception e) { addln(name + ":" + value + ":" + e.toString()); mErrors.add(name + ":" + value + ":" + e.toString()); } } private String PCase(String s) { if (s == null) { return null; } if (s.length() > 0) { return s.substring(0, 1).toUpperCase() + s.substring(1); } return ""; } private Method tryMethod(Object o, String name, Class<?>... parameters) { Method result; try { result = o.getClass().getMethod(name, parameters); } catch (Exception e) { result = null; } return result; } public String camelCase(String s) { if (s == null) { return ""; } else if (s.length() < 2) { return s.toUpperCase(); } else { return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } } private Integer getInteger(Class<?> clazz, String value) { Integer result = null; if (value.contains("|")) { int work = 0; for (String s : value.split("\\|")) { work |= getInteger(clazz, s); } result = work; } else { if (value.startsWith("?")) { result = parseTheme(value); } else if (value.startsWith("@")) { result = parseTheme(value); } else if (value.startsWith("0x")) { try { result = (int) Long.parseLong(value.substring(2), 16); } catch (NumberFormatException e) { result = 0; } } else { try { result = Integer.parseInt(value); } catch (NumberFormatException e) { if (clazz == InputType.class) { return getInputType(value); } try { Field f = clazz.getField(value.toUpperCase()); result = f.getInt(null); } catch (Exception ex) { mErrors.add("Unknown value: " + value); result = 0; } } } } return result; } private Integer getInteger(View view, String value) { return getInteger(view.getClass(), value); } private Integer parseTheme(String value) { int result; try { String query = ""; int i; value = value.substring(1); // skip past "?" i = value.indexOf(":"); if (i >= 0) { query = value.substring(0, i) + "."; value = value.substring(i + 1); } query += "R"; i = value.indexOf("/"); if (i >= 0) { query += "$" + value.substring(0, i); value = value.substring(i + 1); } Class<?> clazz = Class.forName(query); Field f = clazz.getField(value); result = f.getInt(null); } catch (Exception e) { result = 0; } return result; } private View viewClass(Context context, String name) { View result = null; result = viewClassTry(context, "android.view." + name); if (result == null) { result = viewClassTry(context, "android.widget." + name); } if (result == null) { result = viewClassTry(context, name); } return result; } private View viewClassTry(Context context, String name) { View result = null; try { Class<? extends View> viewclass = Class.forName(name).asSubclass( View.class); if (viewclass != null) { Constructor<? extends View> ct = viewclass .getConstructor(Context.class); result = ct.newInstance(context); } } catch (Exception e) { } return result; } public Map<String, Integer> getIdList() { return mIdList; } public List<String> getErrors() { return mErrors; } public String getIdName(int id) { for (String key : mIdList.keySet()) { if (mIdList.get(key) == id) { return key; } } return null; } public int getId(String name) { return mIdList.get(name); } public Map<String, Map<String, String>> getViewAsMap(View v) { Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>(); for (Entry<String, Integer> entry : mIdList.entrySet()) { View tmp = v.findViewById(entry.getValue()); if (tmp != null) { result.put(entry.getKey(), getViewInfo(tmp)); } } return result; } public Map<String, String> getViewInfo(View v) { Map<String, String> result = new HashMap<String, String>(); if (v.getId() != 0) { result.put("id", getIdName(v.getId())); } result.put("type", v.getClass().getSimpleName()); addProperty(v, "text", result); addProperty(v, "visibility", result); addProperty(v, "checked", result); addProperty(v, "tag", result); addProperty(v, "selectedItemPosition", result); addProperty(v, "progress", result); return result; } private void addProperty(View v, String attr, Map<String, String> dest) { String result = getProperty(v, attr); if (result != null) { dest.put(attr, result); } } private String getProperty(View v, String attr) { String name = PCase(attr); Method m = tryMethod(v, "get" + name); if (m == null) { m = tryMethod(v, "is" + name); } String result = null; if (m != null) { try { Object o = m.invoke(v); if (o != null) { result = o.toString(); } } catch (Exception e) { result = null; } } return result; } public static Map<String, Integer> getInputTypes() { if (mInputTypes.size() == 0) { mInputTypes.put("none", 0x00000000); mInputTypes.put("text", 0x00000001); mInputTypes.put("textCapCharacters", 0x00001001); mInputTypes.put("textCapWords", 0x00002001); mInputTypes.put("textCapSentences", 0x00004001); mInputTypes.put("textAutoCorrect", 0x00008001); mInputTypes.put("textAutoComplete", 0x00010001); mInputTypes.put("textMultiLine", 0x00020001); mInputTypes.put("textImeMultiLine", 0x00040001); mInputTypes.put("textNoSuggestions", 0x00080001); mInputTypes.put("textUri", 0x00000011); mInputTypes.put("textEmailAddress", 0x00000021); mInputTypes.put("textEmailSubject", 0x00000031); mInputTypes.put("textShortMessage", 0x00000041); mInputTypes.put("textLongMessage", 0x00000051); mInputTypes.put("textPersonName", 0x00000061); mInputTypes.put("textPostalAddress", 0x00000071); mInputTypes.put("textPassword", 0x00000081); mInputTypes.put("textVisiblePassword", 0x00000091); mInputTypes.put("textWebEditText", 0x000000a1); mInputTypes.put("textFilter", 0x000000b1); mInputTypes.put("textPhonetic", 0x000000c1); mInputTypes.put("textWebEmailAddress", 0x000000d1); mInputTypes.put("textWebPassword", 0x000000e1); mInputTypes.put("number", 0x00000002); mInputTypes.put("numberSigned", 0x00001002); mInputTypes.put("numberDecimal", 0x00002002); mInputTypes.put("numberPassword", 0x00000012); mInputTypes.put("phone", 0x00000003); mInputTypes.put("datetime", 0x00000004); mInputTypes.put("date", 0x00000014); mInputTypes.put("time", 0x00000024); } return mInputTypes; } /** Query class (typically R.id) to extract id names */ public void setIdList(Class<?> idClass) { mIdList.clear(); for (Field f : idClass.getDeclaredFields()) { try { String name = f.getName(); int value = f.getInt(null); mIdList.put(name, value); } catch (Exception e) { // Ignore } } } public void setListAdapter(View view, JSONArray items) { List<String> list = new ArrayList<String>(); try { for (int i = 0; i < items.length(); i++) { list.add(items.get(i).toString()); } ArrayAdapter<String> adapter; if (view instanceof Spinner) { adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_spinner_item, android.R.id.text1, list); } else { adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1, android.R.id.text1, list); } adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); Method m = tryMethod(view, "setAdapter", SpinnerAdapter.class); if (m == null) { m = view.getClass().getMethod("setAdapter", ListAdapter.class); } m.invoke(view, adapter); } catch (Exception e) { mErrors.add("failed to load list " + e.getMessage()); } } public void clearAll() { getErrors().clear(); mIdList.clear(); mNextSeq = BASESEQ; } }