blob: 6d80cc47ccb089a1f7e8360bd2daca7e6bf19b49 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_util_AssetManager.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "asset"
19
Dianne Hackbornb8d81672009-11-20 14:26:42 -080020#define DEBUG_STYLES(x) //x
Dianne Hackborn20cb56e2010-03-04 00:58:29 -080021#define THROW_ON_BAD_ID 0
Dianne Hackbornb8d81672009-11-20 14:26:42 -080022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <android_runtime/android_util_AssetManager.h>
24
25#include "jni.h"
26#include "JNIHelp.h"
27#include "android_util_Binder.h"
28#include <utils/misc.h>
29#include <android_runtime/AndroidRuntime.h>
30#include <utils/Log.h>
31
32#include <utils/Asset.h>
33#include <utils/AssetManager.h>
34#include <utils/ResourceTypes.h>
35
36#include <stdio.h>
37
38namespace android {
39
40// ----------------------------------------------------------------------------
41
42static struct typedvalue_offsets_t
43{
44 jfieldID mType;
45 jfieldID mData;
46 jfieldID mString;
47 jfieldID mAssetCookie;
48 jfieldID mResourceId;
49 jfieldID mChangingConfigurations;
50 jfieldID mDensity;
51} gTypedValueOffsets;
52
53static struct assetfiledescriptor_offsets_t
54{
55 jfieldID mFd;
56 jfieldID mStartOffset;
57 jfieldID mLength;
58} gAssetFileDescriptorOffsets;
59
60static struct assetmanager_offsets_t
61{
62 jfieldID mObject;
63} gAssetManagerOffsets;
64
65jclass g_stringClass = NULL;
66
67// ----------------------------------------------------------------------------
68
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -070070 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 STYLE_TYPE = 0,
72 STYLE_DATA = 1,
73 STYLE_ASSET_COOKIE = 2,
74 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -070075 STYLE_CHANGING_CONFIGURATIONS = 4,
76 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077};
78
79static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
80 const Res_value& value, uint32_t ref, ssize_t block,
81 uint32_t typeSpecFlags, ResTable_config* config = NULL);
82
83jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
84 const Res_value& value, uint32_t ref, ssize_t block,
85 uint32_t typeSpecFlags, ResTable_config* config)
86{
87 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
88 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
89 (jint)table->getTableCookie(block));
90 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
91 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
92 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
93 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
94 typeSpecFlags);
95 if (config != NULL) {
96 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
97 }
98 return block;
99}
100
101// ----------------------------------------------------------------------------
102
103// this guy is exported to other jni routines
104AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
105{
106 AssetManager* am = (AssetManager*)env->GetIntField(obj, gAssetManagerOffsets.mObject);
107 if (am != NULL) {
108 return am;
109 }
110 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
111 return NULL;
112}
113
114static jint android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
115 jstring fileName, jint mode)
116{
117 AssetManager* am = assetManagerForJavaObject(env, clazz);
118 if (am == NULL) {
119 return 0;
120 }
121
122 LOGV("openAsset in %p (Java object %p)\n", am, clazz);
123
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700124 if (fileName == NULL) {
125 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 return -1;
127 }
128
129 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
130 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700131 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 return -1;
133 }
134
135 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
136 Asset* a = am->open(fileName8, (Asset::AccessMode)mode);
137
138 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700139 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 env->ReleaseStringUTFChars(fileName, fileName8);
141 return -1;
142 }
143 env->ReleaseStringUTFChars(fileName, fileName8);
144
145 //printf("Created Asset Stream: %p\n", a);
146
147 return (jint)a;
148}
149
150static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
151{
152 off_t startOffset, length;
153 int fd = a->openFileDescriptor(&startOffset, &length);
154 delete a;
155
156 if (fd < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700157 jniThrowException(env, "java/io/FileNotFoundException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 "This file can not be opened as a file descriptor; it is probably compressed");
159 return NULL;
160 }
161
162 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
163 if (offsets == NULL) {
164 close(fd);
165 return NULL;
166 }
167
168 offsets[0] = startOffset;
169 offsets[1] = length;
170
171 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
172
173 jobject fileDesc = newFileDescriptor(env, fd);
174 if (fileDesc == NULL) {
175 close(fd);
176 return NULL;
177 }
178
179 return newParcelFileDescriptor(env, fileDesc);
180}
181
182static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
183 jstring fileName, jlongArray outOffsets)
184{
185 AssetManager* am = assetManagerForJavaObject(env, clazz);
186 if (am == NULL) {
187 return NULL;
188 }
189
190 LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
191
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700192 if (fileName == NULL) {
193 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 return NULL;
195 }
196
197 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
198 Asset* a = am->open(fileName8, Asset::ACCESS_RANDOM);
199
200 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700201 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 env->ReleaseStringUTFChars(fileName, fileName8);
203 return NULL;
204 }
205 env->ReleaseStringUTFChars(fileName, fileName8);
206
207 //printf("Created Asset Stream: %p\n", a);
208
209 return returnParcelFileDescriptor(env, a, outOffsets);
210}
211
212static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
213 jint cookie,
214 jstring fileName,
215 jint mode)
216{
217 AssetManager* am = assetManagerForJavaObject(env, clazz);
218 if (am == NULL) {
219 return 0;
220 }
221
222 LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
223
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700224 if (fileName == NULL) {
225 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 return -1;
227 }
228
229 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
230 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700231 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 return -1;
233 }
234
235 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
236 Asset* a = cookie
237 ? am->openNonAsset((void*)cookie, fileName8, (Asset::AccessMode)mode)
238 : am->openNonAsset(fileName8, (Asset::AccessMode)mode);
239
240 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700241 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 env->ReleaseStringUTFChars(fileName, fileName8);
243 return -1;
244 }
245 env->ReleaseStringUTFChars(fileName, fileName8);
246
247 //printf("Created Asset Stream: %p\n", a);
248
249 return (jint)a;
250}
251
252static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
253 jint cookie,
254 jstring fileName,
255 jlongArray outOffsets)
256{
257 AssetManager* am = assetManagerForJavaObject(env, clazz);
258 if (am == NULL) {
259 return NULL;
260 }
261
262 LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
263
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700264 if (fileName == NULL ) {
265 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 return NULL;
267 }
268
269 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
270 Asset* a = cookie
271 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_RANDOM)
272 : am->openNonAsset(fileName8, Asset::ACCESS_RANDOM);
273
274 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700275 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 env->ReleaseStringUTFChars(fileName, fileName8);
277 return NULL;
278 }
279 env->ReleaseStringUTFChars(fileName, fileName8);
280
281 //printf("Created Asset Stream: %p\n", a);
282
283 return returnParcelFileDescriptor(env, a, outOffsets);
284}
285
286static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
287 jstring fileName)
288{
289 AssetManager* am = assetManagerForJavaObject(env, clazz);
290 if (am == NULL) {
291 return NULL;
292 }
293
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700294 if (fileName == NULL) {
295 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 return NULL;
297 }
298
299 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
300
301 AssetDir* dir = am->openDir(fileName8);
302
303 env->ReleaseStringUTFChars(fileName, fileName8);
304
305 if (dir == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700306 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 return NULL;
308 }
309
310 jclass cls = env->FindClass("java/lang/String");
311 LOG_FATAL_IF(cls == NULL, "No string class?!?");
312 if (cls == NULL) {
313 delete dir;
314 return NULL;
315 }
316
317 size_t N = dir->getFileCount();
318
319 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
320 cls, NULL);
321 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 delete dir;
323 return NULL;
324 }
325
326 for (size_t i=0; i<N; i++) {
327 const String8& name = dir->getFileName(i);
328 jstring str = env->NewStringUTF(name.string());
329 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 delete dir;
331 return NULL;
332 }
333 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700334 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 }
336
337 delete dir;
338
339 return array;
340}
341
342static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
343 jint asset)
344{
345 Asset* a = (Asset*)asset;
346
347 //printf("Destroying Asset Stream: %p\n", a);
348
349 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700350 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 return;
352 }
353
354 delete a;
355}
356
357static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
358 jint asset)
359{
360 Asset* a = (Asset*)asset;
361
362 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700363 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 return -1;
365 }
366
367 uint8_t b;
368 ssize_t res = a->read(&b, 1);
369 return res == 1 ? b : -1;
370}
371
372static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
373 jint asset, jbyteArray bArray,
374 jint off, jint len)
375{
376 Asset* a = (Asset*)asset;
377
378 if (a == NULL || bArray == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700379 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 return -1;
381 }
382
383 if (len == 0) {
384 return 0;
385 }
386
387 jsize bLen = env->GetArrayLength(bArray);
388 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700389 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 return -1;
391 }
392
393 jbyte* b = env->GetByteArrayElements(bArray, NULL);
394 ssize_t res = a->read(b+off, len);
395 env->ReleaseByteArrayElements(bArray, b, 0);
396
397 if (res > 0) return res;
398
399 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700400 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
402 return -1;
403}
404
405static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
406 jint asset,
407 jlong offset, jint whence)
408{
409 Asset* a = (Asset*)asset;
410
411 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700412 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 return -1;
414 }
415
416 return a->seek(
417 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
418}
419
420static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
421 jint asset)
422{
423 Asset* a = (Asset*)asset;
424
425 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700426 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 return -1;
428 }
429
430 return a->getLength();
431}
432
433static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
434 jint asset)
435{
436 Asset* a = (Asset*)asset;
437
438 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700439 jniThrowException(env, "java/lang/NullPointerException", "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 return -1;
441 }
442
443 return a->getRemainingLength();
444}
445
446static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
447 jstring path)
448{
449 if (path == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700450 jniThrowException(env, "java/lang/NullPointerException", "path");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 return JNI_FALSE;
452 }
453
454 AssetManager* am = assetManagerForJavaObject(env, clazz);
455 if (am == NULL) {
456 return JNI_FALSE;
457 }
458
459 const char* path8 = env->GetStringUTFChars(path, NULL);
460
461 void* cookie;
462 bool res = am->addAssetPath(String8(path8), &cookie);
463
464 env->ReleaseStringUTFChars(path, path8);
465
466 return (res) ? (jint)cookie : 0;
467}
468
469static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
470{
471 AssetManager* am = assetManagerForJavaObject(env, clazz);
472 if (am == NULL) {
473 return JNI_TRUE;
474 }
475 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
476}
477
478static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
479 jstring locale)
480{
481 if (locale == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700482 jniThrowException(env, "java/lang/NullPointerException", "locale");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 return;
484 }
485
486 const char* locale8 = env->GetStringUTFChars(locale, NULL);
487
488 AssetManager* am = assetManagerForJavaObject(env, clazz);
489 if (am == NULL) {
490 return;
491 }
492
493 am->setLocale(locale8);
494
495 env->ReleaseStringUTFChars(locale, locale8);
496}
497
498static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
499{
500 Vector<String8> locales;
501
502 AssetManager* am = assetManagerForJavaObject(env, clazz);
503 if (am == NULL) {
504 return NULL;
505 }
506
507 am->getLocales(&locales);
508
509 const int N = locales.size();
510
511 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
512 if (result == NULL) {
513 return NULL;
514 }
515
516 for (int i=0; i<N; i++) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700517 jstring str = env->NewStringUTF(locales[i].string())
518 if (str == NULL) {
519 return NULL;
520 }
521 env->SetObjectArrayElement(result, i, str);
522 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524
525 return result;
526}
527
528static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
529 jint mcc, jint mnc,
530 jstring locale, jint orientation,
531 jint touchscreen, jint density,
532 jint keyboard, jint keyboardHidden,
533 jint navigation,
534 jint screenWidth, jint screenHeight,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100535 jint screenLayout, jint uiMode,
536 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537{
538 AssetManager* am = assetManagerForJavaObject(env, clazz);
539 if (am == NULL) {
540 return;
541 }
542
543 ResTable_config config;
544 memset(&config, 0, sizeof(config));
545
546 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
547
548 config.mcc = (uint16_t)mcc;
549 config.mnc = (uint16_t)mnc;
550 config.orientation = (uint8_t)orientation;
551 config.touchscreen = (uint8_t)touchscreen;
552 config.density = (uint16_t)density;
553 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700554 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 config.navigation = (uint8_t)navigation;
556 config.screenWidth = (uint16_t)screenWidth;
557 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700558 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100559 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 config.sdkVersion = (uint16_t)sdkVersion;
561 config.minorVersion = 0;
562 am->setConfiguration(config, locale8);
563
564 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
565}
566
567static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
568 jstring name,
569 jstring defType,
570 jstring defPackage)
571{
572 if (name == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700573 jniThrowException(env, "java/lang/NullPointerException", "name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 return 0;
575 }
576
577 AssetManager* am = assetManagerForJavaObject(env, clazz);
578 if (am == NULL) {
579 return 0;
580 }
581
582 const char16_t* name16 = env->GetStringChars(name, NULL);
583 jsize nameLen = env->GetStringLength(name);
584 const char16_t* defType16 = defType
585 ? env->GetStringChars(defType, NULL) : NULL;
586 jsize defTypeLen = defType
587 ? env->GetStringLength(defType) : 0;
588 const char16_t* defPackage16 = defPackage
589 ? env->GetStringChars(defPackage, NULL) : NULL;
590 jsize defPackageLen = defPackage
591 ? env->GetStringLength(defPackage) : 0;
592
593 jint ident = am->getResources().identifierForName(
594 name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
595
596 if (defPackage16) {
597 env->ReleaseStringChars(defPackage, defPackage16);
598 }
599 if (defType16) {
600 env->ReleaseStringChars(defType, defType16);
601 }
602 env->ReleaseStringChars(name, name16);
603
604 return ident;
605}
606
607static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
608 jint resid)
609{
610 AssetManager* am = assetManagerForJavaObject(env, clazz);
611 if (am == NULL) {
612 return NULL;
613 }
614
615 ResTable::resource_name name;
616 if (!am->getResources().getResourceName(resid, &name)) {
617 return NULL;
618 }
619
620 String16 str;
621 if (name.package != NULL) {
622 str.setTo(name.package, name.packageLen);
623 }
624 if (name.type != NULL) {
625 if (str.size() > 0) {
626 char16_t div = ':';
627 str.append(&div, 1);
628 }
629 str.append(name.type, name.typeLen);
630 }
631 if (name.name != NULL) {
632 if (str.size() > 0) {
633 char16_t div = '/';
634 str.append(&div, 1);
635 }
636 str.append(name.name, name.nameLen);
637 }
638
639 return env->NewString((const jchar*)str.string(), str.size());
640}
641
642static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
643 jint resid)
644{
645 AssetManager* am = assetManagerForJavaObject(env, clazz);
646 if (am == NULL) {
647 return NULL;
648 }
649
650 ResTable::resource_name name;
651 if (!am->getResources().getResourceName(resid, &name)) {
652 return NULL;
653 }
654
655 if (name.package != NULL) {
656 return env->NewString((const jchar*)name.package, name.packageLen);
657 }
658
659 return NULL;
660}
661
662static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
663 jint resid)
664{
665 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 if (am == NULL) {
667 return NULL;
668 }
669
670 ResTable::resource_name name;
671 if (!am->getResources().getResourceName(resid, &name)) {
672 return NULL;
673 }
674
675 if (name.type != NULL) {
676 return env->NewString((const jchar*)name.type, name.typeLen);
677 }
678
679 return NULL;
680}
681
682static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
683 jint resid)
684{
685 AssetManager* am = assetManagerForJavaObject(env, clazz);
686 if (am == NULL) {
687 return NULL;
688 }
689
690 ResTable::resource_name name;
691 if (!am->getResources().getResourceName(resid, &name)) {
692 return NULL;
693 }
694
695 if (name.name != NULL) {
696 return env->NewString((const jchar*)name.name, name.nameLen);
697 }
698
699 return NULL;
700}
701
702static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
703 jint ident,
704 jobject outValue,
705 jboolean resolve)
706{
707 AssetManager* am = assetManagerForJavaObject(env, clazz);
708 if (am == NULL) {
709 return 0;
710 }
711 const ResTable& res(am->getResources());
712
713 Res_value value;
714 ResTable_config config;
715 uint32_t typeSpecFlags;
716 ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800717#if THROW_ON_BAD_ID
718 if (block == BAD_INDEX) {
719 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
720 return 0;
721 }
722#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 uint32_t ref = ident;
724 if (resolve) {
725 block = res.resolveReference(&value, block, &ref);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800726#if THROW_ON_BAD_ID
727 if (block == BAD_INDEX) {
728 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
729 return 0;
730 }
731#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
734}
735
736static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
737 jint ident, jint bagEntryId,
738 jobject outValue, jboolean resolve)
739{
740 AssetManager* am = assetManagerForJavaObject(env, clazz);
741 if (am == NULL) {
742 return 0;
743 }
744 const ResTable& res(am->getResources());
745
746 // Now lock down the resource object and start pulling stuff from it.
747 res.lock();
748
749 ssize_t block = -1;
750 Res_value value;
751
752 const ResTable::bag_entry* entry = NULL;
753 uint32_t typeSpecFlags;
754 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
755
756 for (ssize_t i=0; i<entryCount; i++) {
757 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
758 block = entry->stringBlock;
759 value = entry->map.value;
760 }
761 entry++;
762 }
763
764 res.unlock();
765
766 if (block < 0) {
767 return block;
768 }
769
770 uint32_t ref = ident;
771 if (resolve) {
772 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800773#if THROW_ON_BAD_ID
774 if (block == BAD_INDEX) {
775 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
776 return 0;
777 }
778#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 }
780 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
781}
782
783static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
784{
785 AssetManager* am = assetManagerForJavaObject(env, clazz);
786 if (am == NULL) {
787 return 0;
788 }
789 return am->getResources().getTableCount();
790}
791
792static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
793 jint block)
794{
795 AssetManager* am = assetManagerForJavaObject(env, clazz);
796 if (am == NULL) {
797 return 0;
798 }
799 return (jint)am->getResources().getTableStringBlock(block);
800}
801
802static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
803 jint cookie)
804{
805 AssetManager* am = assetManagerForJavaObject(env, clazz);
806 if (am == NULL) {
807 return NULL;
808 }
809 String8 name(am->getAssetPath((void*)cookie));
810 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700811 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 return NULL;
813 }
814 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 return str;
816}
817
818static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
819{
820 AssetManager* am = assetManagerForJavaObject(env, clazz);
821 if (am == NULL) {
822 return 0;
823 }
824 return (jint)(new ResTable::Theme(am->getResources()));
825}
826
827static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
828 jint themeInt)
829{
830 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
831 delete theme;
832}
833
834static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
835 jint themeInt,
836 jint styleRes,
837 jboolean force)
838{
839 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
840 theme->applyStyle(styleRes, force ? true : false);
841}
842
843static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
844 jint destInt, jint srcInt)
845{
846 ResTable::Theme* dest = (ResTable::Theme*)destInt;
847 ResTable::Theme* src = (ResTable::Theme*)srcInt;
848 dest->setTo(*src);
849}
850
851static jint android_content_AssetManager_loadThemeAttributeValue(
852 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
853{
854 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
855 const ResTable& res(theme->getResTable());
856
857 Res_value value;
858 // XXX value could be different in different configs!
859 uint32_t typeSpecFlags = 0;
860 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
861 uint32_t ref = 0;
862 if (resolve) {
863 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800864#if THROW_ON_BAD_ID
865 if (block == BAD_INDEX) {
866 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
867 return 0;
868 }
869#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 }
871 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
872}
873
874static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
875 jint themeInt, jint pri,
876 jstring tag, jstring prefix)
877{
878 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
879 const ResTable& res(theme->getResTable());
880
881 if (tag == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700882 jniThrowException(env, "java/lang/NullPointerException", "tag");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return;
884 }
885
886 const char* tag8 = env->GetStringUTFChars(tag, NULL);
887 const char* prefix8 = NULL;
888 if (prefix != NULL) {
889 prefix8 = env->GetStringUTFChars(prefix, NULL);
890 }
891
892 // XXX Need to use params.
893 theme->dumpToLog();
894
895 if (prefix8 != NULL) {
896 env->ReleaseStringUTFChars(prefix, prefix8);
897 }
898 env->ReleaseStringUTFChars(tag, tag8);
899}
900
901static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
902 jint themeToken,
903 jint defStyleAttr,
904 jint defStyleRes,
905 jint xmlParserToken,
906 jintArray attrs,
907 jintArray outValues,
908 jintArray outIndices)
909{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700910 if (themeToken == 0) {
911 jniThrowException(env, "java/lang/NullPointerException", "theme token");
912 return JNI_FALSE;
913 }
914 if (attrs == NULL) {
915 jniThrowException(env, "java/lang/NullPointerException", "attrs");
916 return JNI_FALSE;
917 }
918 if (outValues == NULL) {
919 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 return JNI_FALSE;
921 }
922
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800923 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
924 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
927 const ResTable& res = theme->getResTable();
928 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700929 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 Res_value value;
931
932 const jsize NI = env->GetArrayLength(attrs);
933 const jsize NV = env->GetArrayLength(outValues);
934 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700935 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 return JNI_FALSE;
937 }
938
939 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
940 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700941 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 return JNI_FALSE;
943 }
944
945 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
946 jint* dest = baseDest;
947 if (dest == NULL) {
948 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700949 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 return JNI_FALSE;
951 }
952
953 jint* indices = NULL;
954 int indicesIdx = 0;
955 if (outIndices != NULL) {
956 if (env->GetArrayLength(outIndices) > NI) {
957 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
958 }
959 }
960
961 // Load default style from attribute, if specified...
962 uint32_t defStyleBagTypeSetFlags = 0;
963 if (defStyleAttr != 0) {
964 Res_value value;
965 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
966 if (value.dataType == Res_value::TYPE_REFERENCE) {
967 defStyleRes = value.data;
968 }
969 }
970 }
971
972 // Retrieve the style class associated with the current XML tag.
973 int style = 0;
974 uint32_t styleBagTypeSetFlags = 0;
975 if (xmlParser != NULL) {
976 ssize_t idx = xmlParser->indexOfStyle();
977 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
978 if (value.dataType == value.TYPE_ATTRIBUTE) {
979 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
980 value.dataType = Res_value::TYPE_NULL;
981 }
982 }
983 if (value.dataType == value.TYPE_REFERENCE) {
984 style = value.data;
985 }
986 }
987 }
988
989 // Now lock down the resource object and start pulling stuff from it.
990 res.lock();
991
992 // Retrieve the default style bag, if requested.
993 const ResTable::bag_entry* defStyleEnt = NULL;
994 uint32_t defStyleTypeSetFlags = 0;
995 ssize_t bagOff = defStyleRes != 0
996 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
997 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
998 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
999 (bagOff >= 0 ? bagOff : 0);
1000
1001 // Retrieve the style class bag, if requested.
1002 const ResTable::bag_entry* styleEnt = NULL;
1003 uint32_t styleTypeSetFlags = 0;
1004 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
1005 styleTypeSetFlags |= styleBagTypeSetFlags;
1006 const ResTable::bag_entry* endStyleEnt = styleEnt +
1007 (bagOff >= 0 ? bagOff : 0);
1008
1009 // Retrieve the XML attributes, if requested.
1010 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
1011 jsize ix=0;
1012 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
1013
1014 static const ssize_t kXmlBlock = 0x10000000;
1015
1016 // Now iterate through all of the attributes that the client has requested,
1017 // filling in each with whatever data we can find.
1018 ssize_t block = 0;
1019 uint32_t typeSetFlags;
1020 for (jsize ii=0; ii<NI; ii++) {
1021 const uint32_t curIdent = (uint32_t)src[ii];
1022
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001023 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 // Try to find a value for this attribute... we prioritize values
1026 // coming from, first XML attributes, then XML style, then default
1027 // style, and finally the theme.
1028 value.dataType = Res_value::TYPE_NULL;
1029 value.data = 0;
1030 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001031 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032
1033 // Skip through XML attributes until the end or the next possible match.
1034 while (ix < NX && curIdent > curXmlAttr) {
1035 ix++;
1036 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1037 }
1038 // Retrieve the current XML attribute if it matches, and step to next.
1039 if (ix < NX && curIdent == curXmlAttr) {
1040 block = kXmlBlock;
1041 xmlParser->getAttributeValue(ix, &value);
1042 ix++;
1043 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001044 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1045 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
1047
1048 // Skip through the style values until the end or the next possible match.
1049 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1050 styleEnt++;
1051 }
1052 // Retrieve the current style attribute if it matches, and step to next.
1053 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1054 if (value.dataType == Res_value::TYPE_NULL) {
1055 block = styleEnt->stringBlock;
1056 typeSetFlags = styleTypeSetFlags;
1057 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001058 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1059 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 }
1061 styleEnt++;
1062 }
1063
1064 // Skip through the default style values until the end or the next possible match.
1065 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1066 defStyleEnt++;
1067 }
1068 // Retrieve the current default style attribute if it matches, and step to next.
1069 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1070 if (value.dataType == Res_value::TYPE_NULL) {
1071 block = defStyleEnt->stringBlock;
1072 typeSetFlags = defStyleTypeSetFlags;
1073 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001074 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1075 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 }
1077 defStyleEnt++;
1078 }
1079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 uint32_t resid = 0;
1081 if (value.dataType != Res_value::TYPE_NULL) {
1082 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001083 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1084 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001086 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1087 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 } else {
1089 // If we still don't have a value for this attribute, try to find
1090 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1092 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001093 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1094 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001095 newBlock = res.resolveReference(&value, block, &resid,
1096 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001097#if THROW_ON_BAD_ID
1098 if (newBlock == BAD_INDEX) {
1099 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1100 return JNI_FALSE;
1101 }
1102#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001104 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1105 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 }
1107 }
1108
1109 // Deal with the special @null value -- it turns back to TYPE_NULL.
1110 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001111 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 value.dataType = Res_value::TYPE_NULL;
1113 }
1114
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001115 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1116 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117
1118 // Write the final value back to Java.
1119 dest[STYLE_TYPE] = value.dataType;
1120 dest[STYLE_DATA] = value.data;
1121 dest[STYLE_ASSET_COOKIE] =
1122 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1123 dest[STYLE_RESOURCE_ID] = resid;
1124 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001125 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126
1127 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1128 indicesIdx++;
1129 indices[indicesIdx] = ii;
1130 }
1131
1132 dest += STYLE_NUM_ENTRIES;
1133 }
1134
1135 res.unlock();
1136
1137 if (indices != NULL) {
1138 indices[0] = indicesIdx;
1139 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1140 }
1141 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1142 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1143
1144 return JNI_TRUE;
1145}
1146
1147static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1148 jint xmlParserToken,
1149 jintArray attrs,
1150 jintArray outValues,
1151 jintArray outIndices)
1152{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001153 if (xmlParserToken == 0) {
1154 jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
1155 return JNI_FALSE;
1156 }
1157 if (attrs == NULL) {
1158 jniThrowException(env, "java/lang/NullPointerException", "attrs");
1159 return JNI_FALSE;
1160 }
1161 if (outValues == NULL) {
1162 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 return JNI_FALSE;
1164 }
1165
1166 AssetManager* am = assetManagerForJavaObject(env, clazz);
1167 if (am == NULL) {
1168 return JNI_FALSE;
1169 }
1170 const ResTable& res(am->getResources());
1171 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001172 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 Res_value value;
1174
1175 const jsize NI = env->GetArrayLength(attrs);
1176 const jsize NV = env->GetArrayLength(outValues);
1177 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001178 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 return JNI_FALSE;
1180 }
1181
1182 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1183 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001184 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 return JNI_FALSE;
1186 }
1187
1188 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1189 jint* dest = baseDest;
1190 if (dest == NULL) {
1191 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001192 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 return JNI_FALSE;
1194 }
1195
1196 jint* indices = NULL;
1197 int indicesIdx = 0;
1198 if (outIndices != NULL) {
1199 if (env->GetArrayLength(outIndices) > NI) {
1200 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1201 }
1202 }
1203
1204 // Now lock down the resource object and start pulling stuff from it.
1205 res.lock();
1206
1207 // Retrieve the XML attributes, if requested.
1208 const jsize NX = xmlParser->getAttributeCount();
1209 jsize ix=0;
1210 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1211
1212 static const ssize_t kXmlBlock = 0x10000000;
1213
1214 // Now iterate through all of the attributes that the client has requested,
1215 // filling in each with whatever data we can find.
1216 ssize_t block = 0;
1217 uint32_t typeSetFlags;
1218 for (jsize ii=0; ii<NI; ii++) {
1219 const uint32_t curIdent = (uint32_t)src[ii];
1220
1221 // Try to find a value for this attribute...
1222 value.dataType = Res_value::TYPE_NULL;
1223 value.data = 0;
1224 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001225 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226
1227 // Skip through XML attributes until the end or the next possible match.
1228 while (ix < NX && curIdent > curXmlAttr) {
1229 ix++;
1230 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1231 }
1232 // Retrieve the current XML attribute if it matches, and step to next.
1233 if (ix < NX && curIdent == curXmlAttr) {
1234 block = kXmlBlock;
1235 xmlParser->getAttributeValue(ix, &value);
1236 ix++;
1237 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1238 }
1239
1240 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1241 uint32_t resid = 0;
1242 if (value.dataType != Res_value::TYPE_NULL) {
1243 // Take care of resolving the found resource to its final value.
1244 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001245 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1246 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001247#if THROW_ON_BAD_ID
1248 if (newBlock == BAD_INDEX) {
1249 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1250 return JNI_FALSE;
1251 }
1252#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 if (newBlock >= 0) block = newBlock;
1254 }
1255
1256 // Deal with the special @null value -- it turns back to TYPE_NULL.
1257 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1258 value.dataType = Res_value::TYPE_NULL;
1259 }
1260
1261 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1262
1263 // Write the final value back to Java.
1264 dest[STYLE_TYPE] = value.dataType;
1265 dest[STYLE_DATA] = value.data;
1266 dest[STYLE_ASSET_COOKIE] =
1267 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1268 dest[STYLE_RESOURCE_ID] = resid;
1269 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001270 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271
1272 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1273 indicesIdx++;
1274 indices[indicesIdx] = ii;
1275 }
1276
1277 dest += STYLE_NUM_ENTRIES;
1278 }
1279
1280 res.unlock();
1281
1282 if (indices != NULL) {
1283 indices[0] = indicesIdx;
1284 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1285 }
1286
1287 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1288 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1289
1290 return JNI_TRUE;
1291}
1292
1293static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1294 jint id)
1295{
1296 AssetManager* am = assetManagerForJavaObject(env, clazz);
1297 if (am == NULL) {
1298 return NULL;
1299 }
1300 const ResTable& res(am->getResources());
1301
1302 res.lock();
1303 const ResTable::bag_entry* defStyleEnt = NULL;
1304 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1305 res.unlock();
1306
1307 return bagOff;
1308}
1309
1310static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1311 jint id,
1312 jintArray outValues)
1313{
1314 if (outValues == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001315 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 return JNI_FALSE;
1317 }
1318
1319 AssetManager* am = assetManagerForJavaObject(env, clazz);
1320 if (am == NULL) {
1321 return JNI_FALSE;
1322 }
1323 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001324 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 Res_value value;
1326 ssize_t block;
1327
1328 const jsize NV = env->GetArrayLength(outValues);
1329
1330 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1331 jint* dest = baseDest;
1332 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001333 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 return JNI_FALSE;
1335 }
1336
1337 // Now lock down the resource object and start pulling stuff from it.
1338 res.lock();
1339
1340 const ResTable::bag_entry* arrayEnt = NULL;
1341 uint32_t arrayTypeSetFlags = 0;
1342 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1343 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1344 (bagOff >= 0 ? bagOff : 0);
1345
1346 int i = 0;
1347 uint32_t typeSetFlags;
1348 while (i < NV && arrayEnt < endArrayEnt) {
1349 block = arrayEnt->stringBlock;
1350 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001351 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 value = arrayEnt->map.value;
1353
1354 uint32_t resid = 0;
1355 if (value.dataType != Res_value::TYPE_NULL) {
1356 // Take care of resolving the found resource to its final value.
1357 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001358 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1359 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001360#if THROW_ON_BAD_ID
1361 if (newBlock == BAD_INDEX) {
1362 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1363 return JNI_FALSE;
1364 }
1365#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 if (newBlock >= 0) block = newBlock;
1367 }
1368
1369 // Deal with the special @null value -- it turns back to TYPE_NULL.
1370 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1371 value.dataType = Res_value::TYPE_NULL;
1372 }
1373
1374 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1375
1376 // Write the final value back to Java.
1377 dest[STYLE_TYPE] = value.dataType;
1378 dest[STYLE_DATA] = value.data;
1379 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1380 dest[STYLE_RESOURCE_ID] = resid;
1381 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001382 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 dest += STYLE_NUM_ENTRIES;
1384 i+= STYLE_NUM_ENTRIES;
1385 arrayEnt++;
1386 }
1387
1388 i /= STYLE_NUM_ENTRIES;
1389
1390 res.unlock();
1391
1392 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1393
1394 return i;
1395}
1396
1397static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1398 jint cookie,
1399 jstring fileName)
1400{
1401 AssetManager* am = assetManagerForJavaObject(env, clazz);
1402 if (am == NULL) {
1403 return 0;
1404 }
1405
1406 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1407
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001408 if (fileName == NULL) {
1409 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 return 0;
1411 }
1412
1413 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1414 Asset* a = cookie
1415 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1416 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1417
1418 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001419 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 env->ReleaseStringUTFChars(fileName, fileName8);
1421 return 0;
1422 }
1423 env->ReleaseStringUTFChars(fileName, fileName8);
1424
1425 ResXMLTree* block = new ResXMLTree();
1426 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1427 a->close();
1428 delete a;
1429
1430 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001431 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 return 0;
1433 }
1434
1435 return (jint)block;
1436}
1437
1438static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1439 jint arrayResId)
1440{
1441 AssetManager* am = assetManagerForJavaObject(env, clazz);
1442 if (am == NULL) {
1443 return NULL;
1444 }
1445 const ResTable& res(am->getResources());
1446
1447 const ResTable::bag_entry* startOfBag;
1448 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1449 if (N < 0) {
1450 return NULL;
1451 }
1452
1453 jintArray array = env->NewIntArray(N * 2);
1454 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001455 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 res.unlockBag(startOfBag);
1457 return NULL;
1458 }
1459
1460 Res_value value;
1461 const ResTable::bag_entry* bag = startOfBag;
1462 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1463 jint stringIndex = -1;
1464 jint stringBlock = 0;
1465 value = bag->map.value;
1466
1467 // Take care of resolving the found resource to its final value.
1468 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1469 if (value.dataType == Res_value::TYPE_STRING) {
1470 stringIndex = value.data;
1471 }
1472
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001473#if THROW_ON_BAD_ID
1474 if (stringBlock == BAD_INDEX) {
1475 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1476 return array;
1477 }
1478#endif
1479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 //todo: It might be faster to allocate a C array to contain
1481 // the blocknums and indices, put them in there and then
1482 // do just one SetIntArrayRegion()
1483 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1484 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1485 j = j + 2;
1486 }
1487 res.unlockBag(startOfBag);
1488 return array;
1489}
1490
1491static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1492 jint arrayResId)
1493{
1494 AssetManager* am = assetManagerForJavaObject(env, clazz);
1495 if (am == NULL) {
1496 return NULL;
1497 }
1498 const ResTable& res(am->getResources());
1499
1500 jclass cls = env->FindClass("java/lang/String");
1501 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1502 if (cls == NULL) {
1503 return NULL;
1504 }
1505
1506 const ResTable::bag_entry* startOfBag;
1507 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1508 if (N < 0) {
1509 return NULL;
1510 }
1511
1512 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001513 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 res.unlockBag(startOfBag);
1515 return NULL;
1516 }
1517
1518 Res_value value;
1519 const ResTable::bag_entry* bag = startOfBag;
1520 size_t strLen = 0;
1521 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1522 value = bag->map.value;
1523 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 // Take care of resolving the found resource to its final value.
1526 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001527#if THROW_ON_BAD_ID
1528 if (block == BAD_INDEX) {
1529 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1530 return array;
1531 }
1532#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001534 const ResStringPool* pool = res.getTableStringBlock(block);
1535 const char* str8 = pool->string8At(value.data, &strLen);
1536 if (str8 != NULL) {
1537 str = env->NewStringUTF(str8);
1538 } else {
1539 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1540 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001541 }
1542
1543 // If one of our NewString{UTF} calls failed due to memory, an
1544 // exception will be pending.
1545 if (env->ExceptionCheck()) {
1546 res.unlockBag(startOfBag);
1547 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
Kenny Root780d2a12010-02-22 22:36:26 -08001549
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001550 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001551
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001552 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1553 // If we have a large amount of strings in our array, we might
1554 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001555 env->DeleteLocalRef(str);
1556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 }
1558 res.unlockBag(startOfBag);
1559 return array;
1560}
1561
1562static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1563 jint arrayResId)
1564{
1565 AssetManager* am = assetManagerForJavaObject(env, clazz);
1566 if (am == NULL) {
1567 return NULL;
1568 }
1569 const ResTable& res(am->getResources());
1570
1571 const ResTable::bag_entry* startOfBag;
1572 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1573 if (N < 0) {
1574 return NULL;
1575 }
1576
1577 jintArray array = env->NewIntArray(N);
1578 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001579 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 res.unlockBag(startOfBag);
1581 return NULL;
1582 }
1583
1584 Res_value value;
1585 const ResTable::bag_entry* bag = startOfBag;
1586 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1587 value = bag->map.value;
1588
1589 // Take care of resolving the found resource to its final value.
1590 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001591#if THROW_ON_BAD_ID
1592 if (block == BAD_INDEX) {
1593 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1594 return array;
1595 }
1596#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 if (value.dataType >= Res_value::TYPE_FIRST_INT
1598 && value.dataType <= Res_value::TYPE_LAST_INT) {
1599 int intVal = value.data;
1600 env->SetIntArrayRegion(array, i, 1, &intVal);
1601 }
1602 }
1603 res.unlockBag(startOfBag);
1604 return array;
1605}
1606
1607static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1608{
1609 AssetManager* am = new AssetManager();
1610 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001611 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 return;
1613 }
1614
1615 am->addDefaultAssets();
1616
1617 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1618 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1619}
1620
1621static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1622{
1623 AssetManager* am = (AssetManager*)
1624 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1625 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1626 if (am != NULL) {
1627 delete am;
1628 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1629 }
1630}
1631
1632static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1633{
1634 return Asset::getGlobalCount();
1635}
1636
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001637static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1638{
1639 String8 alloc = Asset::getAssetAllocations();
1640 if (alloc.length() <= 0) {
1641 return NULL;
1642 }
1643
1644 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001645 return str;
1646}
1647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1649{
1650 return AssetManager::getGlobalCount();
1651}
1652
1653// ----------------------------------------------------------------------------
1654
1655/*
1656 * JNI registration.
1657 */
1658static JNINativeMethod gAssetManagerMethods[] = {
1659 /* name, signature, funcPtr */
1660
1661 // Basic asset stuff.
1662 { "openAsset", "(Ljava/lang/String;I)I",
1663 (void*) android_content_AssetManager_openAsset },
1664 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1665 (void*) android_content_AssetManager_openAssetFd },
1666 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1667 (void*) android_content_AssetManager_openNonAssetNative },
1668 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1669 (void*) android_content_AssetManager_openNonAssetFdNative },
1670 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1671 (void*) android_content_AssetManager_list },
1672 { "destroyAsset", "(I)V",
1673 (void*) android_content_AssetManager_destroyAsset },
1674 { "readAssetChar", "(I)I",
1675 (void*) android_content_AssetManager_readAssetChar },
1676 { "readAsset", "(I[BII)I",
1677 (void*) android_content_AssetManager_readAsset },
1678 { "seekAsset", "(IJI)J",
1679 (void*) android_content_AssetManager_seekAsset },
1680 { "getAssetLength", "(I)J",
1681 (void*) android_content_AssetManager_getAssetLength },
1682 { "getAssetRemainingLength", "(I)J",
1683 (void*) android_content_AssetManager_getAssetRemainingLength },
1684 { "addAssetPath", "(Ljava/lang/String;)I",
1685 (void*) android_content_AssetManager_addAssetPath },
1686 { "isUpToDate", "()Z",
1687 (void*) android_content_AssetManager_isUpToDate },
1688
1689 // Resources.
1690 { "setLocale", "(Ljava/lang/String;)V",
1691 (void*) android_content_AssetManager_setLocale },
1692 { "getLocales", "()[Ljava/lang/String;",
1693 (void*) android_content_AssetManager_getLocales },
Tobias Haamel27b28b32010-02-09 23:09:17 +01001694 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 (void*) android_content_AssetManager_setConfiguration },
1696 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1697 (void*) android_content_AssetManager_getResourceIdentifier },
1698 { "getResourceName","(I)Ljava/lang/String;",
1699 (void*) android_content_AssetManager_getResourceName },
1700 { "getResourcePackageName","(I)Ljava/lang/String;",
1701 (void*) android_content_AssetManager_getResourcePackageName },
1702 { "getResourceTypeName","(I)Ljava/lang/String;",
1703 (void*) android_content_AssetManager_getResourceTypeName },
1704 { "getResourceEntryName","(I)Ljava/lang/String;",
1705 (void*) android_content_AssetManager_getResourceEntryName },
1706 { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
1707 (void*) android_content_AssetManager_loadResourceValue },
1708 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1709 (void*) android_content_AssetManager_loadResourceBagValue },
1710 { "getStringBlockCount","()I",
1711 (void*) android_content_AssetManager_getStringBlockCount },
1712 { "getNativeStringBlock","(I)I",
1713 (void*) android_content_AssetManager_getNativeStringBlock },
1714 { "getCookieName","(I)Ljava/lang/String;",
1715 (void*) android_content_AssetManager_getCookieName },
1716
1717 // Themes.
1718 { "newTheme", "()I",
1719 (void*) android_content_AssetManager_newTheme },
1720 { "deleteTheme", "(I)V",
1721 (void*) android_content_AssetManager_deleteTheme },
1722 { "applyThemeStyle", "(IIZ)V",
1723 (void*) android_content_AssetManager_applyThemeStyle },
1724 { "copyTheme", "(II)V",
1725 (void*) android_content_AssetManager_copyTheme },
1726 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1727 (void*) android_content_AssetManager_loadThemeAttributeValue },
1728 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1729 (void*) android_content_AssetManager_dumpTheme },
1730 { "applyStyle","(IIII[I[I[I)Z",
1731 (void*) android_content_AssetManager_applyStyle },
1732 { "retrieveAttributes","(I[I[I[I)Z",
1733 (void*) android_content_AssetManager_retrieveAttributes },
1734 { "getArraySize","(I)I",
1735 (void*) android_content_AssetManager_getArraySize },
1736 { "retrieveArray","(I[I)I",
1737 (void*) android_content_AssetManager_retrieveArray },
1738
1739 // XML files.
1740 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1741 (void*) android_content_AssetManager_openXmlAssetNative },
1742
1743 // Arrays.
1744 { "getArrayStringResource","(I)[Ljava/lang/String;",
1745 (void*) android_content_AssetManager_getArrayStringResource },
1746 { "getArrayStringInfo","(I)[I",
1747 (void*) android_content_AssetManager_getArrayStringInfo },
1748 { "getArrayIntResource","(I)[I",
1749 (void*) android_content_AssetManager_getArrayIntResource },
1750
1751 // Bookkeeping.
1752 { "init", "()V",
1753 (void*) android_content_AssetManager_init },
1754 { "destroy", "()V",
1755 (void*) android_content_AssetManager_destroy },
1756 { "getGlobalAssetCount", "()I",
1757 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001758 { "getAssetAllocations", "()Ljava/lang/String;",
1759 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 { "getGlobalAssetManagerCount", "()I",
1761 (void*) android_content_AssetManager_getGlobalAssetCount },
1762};
1763
1764int register_android_content_AssetManager(JNIEnv* env)
1765{
1766 jclass typedValue = env->FindClass("android/util/TypedValue");
1767 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1768 gTypedValueOffsets.mType
1769 = env->GetFieldID(typedValue, "type", "I");
1770 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1771 gTypedValueOffsets.mData
1772 = env->GetFieldID(typedValue, "data", "I");
1773 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1774 gTypedValueOffsets.mString
1775 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1776 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1777 gTypedValueOffsets.mAssetCookie
1778 = env->GetFieldID(typedValue, "assetCookie", "I");
1779 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1780 gTypedValueOffsets.mResourceId
1781 = env->GetFieldID(typedValue, "resourceId", "I");
1782 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1783 gTypedValueOffsets.mChangingConfigurations
1784 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1785 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1786 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1787 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1788
1789 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1790 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1791 gAssetFileDescriptorOffsets.mFd
1792 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1793 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1794 gAssetFileDescriptorOffsets.mStartOffset
1795 = env->GetFieldID(assetFd, "mStartOffset", "J");
1796 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1797 gAssetFileDescriptorOffsets.mLength
1798 = env->GetFieldID(assetFd, "mLength", "J");
1799 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1800
1801 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1802 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1803 gAssetManagerOffsets.mObject
1804 = env->GetFieldID(assetManager, "mObject", "I");
1805 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1806
1807 g_stringClass = env->FindClass("java/lang/String");
1808
1809 return AndroidRuntime::registerNativeMethods(env,
1810 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1811}
1812
1813}; // namespace android