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