Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.os.Build.VERSION_CODES.P;
      4 import static org.robolectric.res.android.Errors.NO_ERROR;
      5 
      6 import android.os.Build;
      7 import android.os.Build.VERSION_CODES;
      8 import org.robolectric.RuntimeEnvironment;
      9 import org.robolectric.annotation.Implementation;
     10 import org.robolectric.annotation.Implements;
     11 import org.robolectric.res.android.Ref;
     12 import org.robolectric.res.android.Registries;
     13 import org.robolectric.res.android.ResXMLParser;
     14 import org.robolectric.res.android.ResXMLTree;
     15 import org.robolectric.res.android.ResourceTypes.Res_value;
     16 import org.xmlpull.v1.XmlPullParserException;
     17 
     18 @Implements(className = "android.content.res.XmlBlock", isInAndroidSdk = false)
     19 public class ShadowXmlBlock {
     20 
     21   @Implementation
     22   protected static Number nativeCreate(byte[] bArray, int off, int len) {
     23     if (bArray == null) {
     24       throw new NullPointerException();
     25     }
     26 
     27     int bLen = bArray.length;
     28     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
     29       throw new IndexOutOfBoundsException();
     30     }
     31 
     32     // todo: optimize
     33     byte[] b = new byte[len];
     34     System.arraycopy(bArray, off, b, 0, len);
     35 
     36     ResXMLTree osb = new ResXMLTree(null);
     37     osb.setTo(b, len, true);
     38 //    env->ReleaseByteArrayElements(bArray, b, 0);
     39 
     40     if (osb.getError() != NO_ERROR) {
     41       throw new IllegalArgumentException();
     42     }
     43 
     44     return RuntimeEnvironment.castNativePtr(Registries.NATIVE_RES_XML_TREES.register(osb));
     45   }
     46 
     47   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
     48   protected static int nativeGetStringBlock(int obj) {
     49     return (int)nativeGetStringBlock((long)obj);
     50   }
     51 
     52   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
     53   protected static Number nativeGetStringBlock(long obj) {
     54     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
     55 //    if (osb == NULL) {
     56 //      jniThrowNullPointerException(env, NULL);
     57 //      return 0;
     58 //    }
     59 
     60     return RuntimeEnvironment.castNativePtr(osb.getStrings().getNativePtr());
     61   }
     62 
     63   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
     64   protected static int nativeCreateParseState(int obj) {
     65     return (int)nativeCreateParseState((long)obj);
     66   }
     67 
     68   @Implementation(minSdk = VERSION_CODES.LOLLIPOP, maxSdk = P)
     69   protected static long nativeCreateParseState(long obj) {
     70     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
     71 //    if (osb == NULL) {
     72 //      jniThrowNullPointerException(env, NULL);
     73 //      return 0;
     74 //    }
     75 
     76     ResXMLParser st = new ResXMLParser(osb);
     77 //    if (st == NULL) {
     78 //      jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
     79 //      return 0;
     80 //    }
     81 
     82     st.restart();
     83 
     84     return Registries.NATIVE_RES_XML_PARSERS.register(st);
     85   }
     86 
     87   // BEGIN-INTERNAL
     88   @Implementation(minSdk = Build.VERSION_CODES.Q)
     89   protected static long nativeCreateParseState(long obj, int resid) {
     90     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
     91 //    if (osb == NULL) {
     92 //      jniThrowNullPointerException(env, NULL);
     93 //      return 0;
     94 //    }
     95 
     96     ResXMLParser st = new ResXMLParser(osb);
     97 //    if (st == NULL) {
     98 //      jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
     99 //      return 0;
    100 //    }
    101 
    102     st.restart();
    103 
    104     return Registries.NATIVE_RES_XML_PARSERS.register(st);
    105   }
    106   // END-INTERNAL
    107 
    108   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    109   protected static int nativeNext(int state) throws XmlPullParserException {
    110     return (int)nativeNext((long)state);
    111   }
    112 
    113   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    114   protected static int nativeNext(long state) throws XmlPullParserException {
    115     ResXMLParser st = getResXMLParser(state);
    116     if (st == null) {
    117       return ResXMLParser.event_code_t.END_DOCUMENT;
    118     }
    119 
    120     do {
    121       int code = st.next();
    122       switch (code) {
    123         case ResXMLParser.event_code_t.START_TAG:
    124           return 2;
    125         case ResXMLParser.event_code_t.END_TAG:
    126           return 3;
    127         case ResXMLParser.event_code_t.TEXT:
    128           return 4;
    129         case ResXMLParser.event_code_t.START_DOCUMENT:
    130           return 0;
    131         case ResXMLParser.event_code_t.END_DOCUMENT:
    132           return 1;
    133         case ResXMLParser.event_code_t.BAD_DOCUMENT:
    134 //                goto bad;
    135           throw new XmlPullParserException("Corrupt XML binary file");
    136         default:
    137           break;
    138       }
    139 
    140     } while (true);
    141   }
    142 
    143   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    144   protected static int nativeGetNamespace(int state) {
    145     return nativeGetNamespace((long)state);
    146   }
    147 
    148   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    149   protected static int nativeGetNamespace(long state) {
    150     ResXMLParser resXMLParser = getResXMLParser(state);
    151     return resXMLParser.getElementNamespaceID();
    152   }
    153 
    154   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    155   protected static int nativeGetName(int state) {
    156     return (int)nativeGetName((long)state);
    157   }
    158 
    159   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    160   protected static int nativeGetName(long state) {
    161     ResXMLParser resXMLParser = getResXMLParser(state);
    162     return resXMLParser.getElementNameID();
    163   }
    164 
    165   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    166   protected static int nativeGetText(int state) {
    167     return (int)nativeGetText((long)state);
    168   }
    169 
    170   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    171   protected static int nativeGetText(long state) {
    172     ResXMLParser resXMLParser = getResXMLParser(state);
    173     return resXMLParser.getTextID();
    174   }
    175 
    176   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    177   protected static int nativeGetLineNumber(int state) {
    178     return (int)nativeGetLineNumber((long)state);
    179   }
    180 
    181   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    182   protected static int nativeGetLineNumber(long state) {
    183     ResXMLParser resXMLParser = getResXMLParser(state);
    184     return resXMLParser.getLineNumber();
    185   }
    186 
    187   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    188   protected static int nativeGetAttributeCount(int state) {
    189     return (int)nativeGetAttributeCount((long)state);
    190   }
    191 
    192   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    193   protected static int nativeGetAttributeCount(long state) {
    194     ResXMLParser resXMLParser = getResXMLParser(state);
    195     return resXMLParser.getAttributeCount();
    196   }
    197 
    198   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    199   protected static int nativeGetAttributeNamespace(int state, int idx) {
    200     return (int)nativeGetAttributeNamespace((long)state, idx);
    201   }
    202 
    203   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    204   protected static int nativeGetAttributeNamespace(long state, int idx) {
    205     ResXMLParser resXMLParser = getResXMLParser(state);
    206     return resXMLParser.getAttributeNamespaceID(idx);
    207   }
    208 
    209   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    210   protected static int nativeGetAttributeName(int state, int idx) {
    211     return (int)nativeGetAttributeName((long) state, idx);
    212   }
    213 
    214   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    215   protected static int nativeGetAttributeName(long state, int idx) {
    216     ResXMLParser resXMLParser = getResXMLParser(state);
    217     return resXMLParser.getAttributeNameID(idx);
    218   }
    219 
    220   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    221   protected static int nativeGetAttributeResource(int state, int idx) {
    222     return (int)nativeGetAttributeResource((long)state, idx);
    223   }
    224 
    225   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    226   protected static int nativeGetAttributeResource(long state, int idx) {
    227     ResXMLParser resXMLParser = getResXMLParser(state);
    228     return resXMLParser.getAttributeNameResID(idx);
    229   }
    230 
    231   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    232   protected static int nativeGetAttributeDataType(int state, int idx) {
    233     return (int)nativeGetAttributeDataType((long)state, idx);
    234   }
    235 
    236   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    237   protected static int nativeGetAttributeDataType(long state, int idx) {
    238     ResXMLParser resXMLParser = getResXMLParser(state);
    239     return resXMLParser.getAttributeDataType(idx);
    240   }
    241 
    242   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    243   protected static int nativeGetAttributeData(int state, int idx) {
    244     return (int)nativeGetAttributeData((long)state, idx);
    245   }
    246 
    247   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    248   protected static int nativeGetAttributeData(long state, int idx) {
    249     ResXMLParser resXMLParser = getResXMLParser(state);
    250     return resXMLParser.getAttributeData(idx);
    251   }
    252 
    253   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    254   protected static int nativeGetAttributeStringValue(int state, int idx) {
    255     return (int)nativeGetAttributeStringValue((long)state, idx);
    256   }
    257 
    258   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    259   protected static int nativeGetAttributeStringValue(long state, int idx) {
    260     ResXMLParser resXMLParser = getResXMLParser(state);
    261     return resXMLParser.getAttributeValueStringID(idx);
    262   }
    263 
    264   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    265   protected static int nativeGetIdAttribute(int obj) {
    266     return (int)nativeGetIdAttribute((long)obj);
    267   }
    268 
    269   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    270   protected static int nativeGetIdAttribute(long state) {
    271     ResXMLParser resXMLParser = getResXMLParser(state);
    272     int idx = resXMLParser.indexOfID();
    273     return idx >= 0 ? resXMLParser.getAttributeValueStringID(idx) : -1;
    274   }
    275 
    276   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    277   protected static int nativeGetClassAttribute(int obj) {
    278     return (int)nativeGetClassAttribute((long)obj);
    279   }
    280 
    281   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    282   protected static int nativeGetClassAttribute(long state) {
    283     ResXMLParser resXMLParser = getResXMLParser(state);
    284     int idx = resXMLParser.indexOfClass();
    285     return idx >= 0 ? resXMLParser.getAttributeValueStringID(idx) : -1;
    286   }
    287 
    288   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    289   protected static int nativeGetStyleAttribute(int obj) {
    290     return (int)nativeGetStyleAttribute((long)obj);
    291   }
    292 
    293   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    294   protected static int nativeGetStyleAttribute(long state) {
    295     ResXMLParser resXMLParser = getResXMLParser(state);
    296     int idx = resXMLParser.indexOfStyle();
    297     if (idx < 0) {
    298       return 0;
    299     }
    300 
    301     final Ref<Res_value> valueRef = new Ref<>(new Res_value());
    302     if (resXMLParser.getAttributeValue(idx, valueRef) < 0) {
    303       return 0;
    304     }
    305     Res_value value = valueRef.get();
    306 
    307     return value.dataType == org.robolectric.res.android.ResourceTypes.Res_value.TYPE_REFERENCE
    308         || value.dataType == org.robolectric.res.android.ResourceTypes.Res_value.TYPE_ATTRIBUTE
    309         ? value.data : 0;
    310   }
    311 
    312   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    313   protected static int nativeGetAttributeIndex(int obj, String ns, String name) {
    314     return (int)nativeGetAttributeIndex((long)obj, ns, name);
    315   }
    316 
    317   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    318   protected static int nativeGetAttributeIndex(long token, String ns, String name) {
    319     ResXMLParser st = getResXMLParser(token);
    320     if (st == null || name == null) {
    321       throw new NullPointerException();
    322     }
    323 
    324     int nsLen = 0;
    325     if (ns != null) {
    326       nsLen = ns.length();
    327     }
    328 
    329     return st.indexOfAttribute(ns, nsLen, name, name.length());
    330   }
    331 
    332   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    333   protected static void nativeDestroyParseState(int obj) {
    334     nativeDestroyParseState((long)obj);
    335   }
    336 
    337   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    338   protected static void nativeDestroyParseState(long state) {
    339     Registries.NATIVE_RES_XML_PARSERS.unregister(state);
    340   }
    341 
    342   @Implementation(maxSdk = VERSION_CODES.KITKAT_WATCH)
    343   protected static void nativeDestroy(int obj) {
    344     nativeDestroy((long)obj);
    345   }
    346 
    347   @Implementation(minSdk = VERSION_CODES.LOLLIPOP)
    348   protected static void nativeDestroy(long obj) {
    349     Registries.NATIVE_RES_XML_TREES.unregister(obj);
    350   }
    351 
    352   private static ResXMLParser getResXMLParser(long state) {
    353     return Registries.NATIVE_RES_XML_PARSERS.getNativeObject(state);
    354   }
    355 }
    356