blob: 1bce332d6127dcb726c5b67627d215fb5f8be426 [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{
Kenny Rootddb76c42010-11-24 12:56:06 -0800152 off64_t startOffset, length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 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 Debunne0db187a2010-08-27 11:51:34 -0700517 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700518 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,
Kenny Root55fc8502010-10-28 14:47:01 -0700704 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 jobject outValue,
706 jboolean resolve)
707{
708 AssetManager* am = assetManagerForJavaObject(env, clazz);
709 if (am == NULL) {
710 return 0;
711 }
712 const ResTable& res(am->getResources());
713
714 Res_value value;
715 ResTable_config config;
716 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700717 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800718#if THROW_ON_BAD_ID
719 if (block == BAD_INDEX) {
720 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
721 return 0;
722 }
723#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 uint32_t ref = ident;
725 if (resolve) {
726 block = res.resolveReference(&value, block, &ref);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800727#if THROW_ON_BAD_ID
728 if (block == BAD_INDEX) {
729 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
730 return 0;
731 }
732#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 }
734 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
735}
736
737static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
738 jint ident, jint bagEntryId,
739 jobject outValue, jboolean resolve)
740{
741 AssetManager* am = assetManagerForJavaObject(env, clazz);
742 if (am == NULL) {
743 return 0;
744 }
745 const ResTable& res(am->getResources());
746
747 // Now lock down the resource object and start pulling stuff from it.
748 res.lock();
749
750 ssize_t block = -1;
751 Res_value value;
752
753 const ResTable::bag_entry* entry = NULL;
754 uint32_t typeSpecFlags;
755 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
756
757 for (ssize_t i=0; i<entryCount; i++) {
758 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
759 block = entry->stringBlock;
760 value = entry->map.value;
761 }
762 entry++;
763 }
764
765 res.unlock();
766
767 if (block < 0) {
768 return block;
769 }
770
771 uint32_t ref = ident;
772 if (resolve) {
773 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800774#if THROW_ON_BAD_ID
775 if (block == BAD_INDEX) {
776 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
777 return 0;
778 }
779#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
781 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
782}
783
784static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
785{
786 AssetManager* am = assetManagerForJavaObject(env, clazz);
787 if (am == NULL) {
788 return 0;
789 }
790 return am->getResources().getTableCount();
791}
792
793static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
794 jint block)
795{
796 AssetManager* am = assetManagerForJavaObject(env, clazz);
797 if (am == NULL) {
798 return 0;
799 }
800 return (jint)am->getResources().getTableStringBlock(block);
801}
802
803static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
804 jint cookie)
805{
806 AssetManager* am = assetManagerForJavaObject(env, clazz);
807 if (am == NULL) {
808 return NULL;
809 }
810 String8 name(am->getAssetPath((void*)cookie));
811 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700812 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 return NULL;
814 }
815 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 return str;
817}
818
819static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
820{
821 AssetManager* am = assetManagerForJavaObject(env, clazz);
822 if (am == NULL) {
823 return 0;
824 }
825 return (jint)(new ResTable::Theme(am->getResources()));
826}
827
828static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
829 jint themeInt)
830{
831 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
832 delete theme;
833}
834
835static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
836 jint themeInt,
837 jint styleRes,
838 jboolean force)
839{
840 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
841 theme->applyStyle(styleRes, force ? true : false);
842}
843
844static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
845 jint destInt, jint srcInt)
846{
847 ResTable::Theme* dest = (ResTable::Theme*)destInt;
848 ResTable::Theme* src = (ResTable::Theme*)srcInt;
849 dest->setTo(*src);
850}
851
852static jint android_content_AssetManager_loadThemeAttributeValue(
853 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
854{
855 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
856 const ResTable& res(theme->getResTable());
857
858 Res_value value;
859 // XXX value could be different in different configs!
860 uint32_t typeSpecFlags = 0;
861 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
862 uint32_t ref = 0;
863 if (resolve) {
864 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800865#if THROW_ON_BAD_ID
866 if (block == BAD_INDEX) {
867 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
868 return 0;
869 }
870#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
873}
874
875static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
876 jint themeInt, jint pri,
877 jstring tag, jstring prefix)
878{
879 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
880 const ResTable& res(theme->getResTable());
881
882 if (tag == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700883 jniThrowException(env, "java/lang/NullPointerException", "tag");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 return;
885 }
886
887 const char* tag8 = env->GetStringUTFChars(tag, NULL);
888 const char* prefix8 = NULL;
889 if (prefix != NULL) {
890 prefix8 = env->GetStringUTFChars(prefix, NULL);
891 }
892
893 // XXX Need to use params.
894 theme->dumpToLog();
895
896 if (prefix8 != NULL) {
897 env->ReleaseStringUTFChars(prefix, prefix8);
898 }
899 env->ReleaseStringUTFChars(tag, tag8);
900}
901
902static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
903 jint themeToken,
904 jint defStyleAttr,
905 jint defStyleRes,
906 jint xmlParserToken,
907 jintArray attrs,
908 jintArray outValues,
909 jintArray outIndices)
910{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700911 if (themeToken == 0) {
912 jniThrowException(env, "java/lang/NullPointerException", "theme token");
913 return JNI_FALSE;
914 }
915 if (attrs == NULL) {
916 jniThrowException(env, "java/lang/NullPointerException", "attrs");
917 return JNI_FALSE;
918 }
919 if (outValues == NULL) {
920 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 return JNI_FALSE;
922 }
923
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800924 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
925 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
928 const ResTable& res = theme->getResTable();
929 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700930 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 Res_value value;
932
933 const jsize NI = env->GetArrayLength(attrs);
934 const jsize NV = env->GetArrayLength(outValues);
935 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700936 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 return JNI_FALSE;
938 }
939
940 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
941 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700942 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 return JNI_FALSE;
944 }
945
946 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
947 jint* dest = baseDest;
948 if (dest == NULL) {
949 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700950 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 return JNI_FALSE;
952 }
953
954 jint* indices = NULL;
955 int indicesIdx = 0;
956 if (outIndices != NULL) {
957 if (env->GetArrayLength(outIndices) > NI) {
958 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
959 }
960 }
961
962 // Load default style from attribute, if specified...
963 uint32_t defStyleBagTypeSetFlags = 0;
964 if (defStyleAttr != 0) {
965 Res_value value;
966 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
967 if (value.dataType == Res_value::TYPE_REFERENCE) {
968 defStyleRes = value.data;
969 }
970 }
971 }
972
973 // Retrieve the style class associated with the current XML tag.
974 int style = 0;
975 uint32_t styleBagTypeSetFlags = 0;
976 if (xmlParser != NULL) {
977 ssize_t idx = xmlParser->indexOfStyle();
978 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
979 if (value.dataType == value.TYPE_ATTRIBUTE) {
980 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
981 value.dataType = Res_value::TYPE_NULL;
982 }
983 }
984 if (value.dataType == value.TYPE_REFERENCE) {
985 style = value.data;
986 }
987 }
988 }
989
990 // Now lock down the resource object and start pulling stuff from it.
991 res.lock();
992
993 // Retrieve the default style bag, if requested.
994 const ResTable::bag_entry* defStyleEnt = NULL;
995 uint32_t defStyleTypeSetFlags = 0;
996 ssize_t bagOff = defStyleRes != 0
997 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
998 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
999 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1000 (bagOff >= 0 ? bagOff : 0);
1001
1002 // Retrieve the style class bag, if requested.
1003 const ResTable::bag_entry* styleEnt = NULL;
1004 uint32_t styleTypeSetFlags = 0;
1005 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
1006 styleTypeSetFlags |= styleBagTypeSetFlags;
1007 const ResTable::bag_entry* endStyleEnt = styleEnt +
1008 (bagOff >= 0 ? bagOff : 0);
1009
1010 // Retrieve the XML attributes, if requested.
1011 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
1012 jsize ix=0;
1013 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
1014
1015 static const ssize_t kXmlBlock = 0x10000000;
1016
1017 // Now iterate through all of the attributes that the client has requested,
1018 // filling in each with whatever data we can find.
1019 ssize_t block = 0;
1020 uint32_t typeSetFlags;
1021 for (jsize ii=0; ii<NI; ii++) {
1022 const uint32_t curIdent = (uint32_t)src[ii];
1023
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001024 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 // Try to find a value for this attribute... we prioritize values
1027 // coming from, first XML attributes, then XML style, then default
1028 // style, and finally the theme.
1029 value.dataType = Res_value::TYPE_NULL;
1030 value.data = 0;
1031 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001032 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033
1034 // Skip through XML attributes until the end or the next possible match.
1035 while (ix < NX && curIdent > curXmlAttr) {
1036 ix++;
1037 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1038 }
1039 // Retrieve the current XML attribute if it matches, and step to next.
1040 if (ix < NX && curIdent == curXmlAttr) {
1041 block = kXmlBlock;
1042 xmlParser->getAttributeValue(ix, &value);
1043 ix++;
1044 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001045 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1046 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 }
1048
1049 // Skip through the style values until the end or the next possible match.
1050 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1051 styleEnt++;
1052 }
1053 // Retrieve the current style attribute if it matches, and step to next.
1054 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1055 if (value.dataType == Res_value::TYPE_NULL) {
1056 block = styleEnt->stringBlock;
1057 typeSetFlags = styleTypeSetFlags;
1058 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001059 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1060 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062 styleEnt++;
1063 }
1064
1065 // Skip through the default style values until the end or the next possible match.
1066 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1067 defStyleEnt++;
1068 }
1069 // Retrieve the current default style attribute if it matches, and step to next.
1070 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1071 if (value.dataType == Res_value::TYPE_NULL) {
1072 block = defStyleEnt->stringBlock;
1073 typeSetFlags = defStyleTypeSetFlags;
1074 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001075 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1076 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078 defStyleEnt++;
1079 }
1080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 uint32_t resid = 0;
1082 if (value.dataType != Res_value::TYPE_NULL) {
1083 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001084 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1085 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001087 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1088 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 } else {
1090 // If we still don't have a value for this attribute, try to find
1091 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1093 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001094 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1095 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001096 newBlock = res.resolveReference(&value, block, &resid,
1097 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001098#if THROW_ON_BAD_ID
1099 if (newBlock == BAD_INDEX) {
1100 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1101 return JNI_FALSE;
1102 }
1103#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001105 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1106 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
1108 }
1109
1110 // Deal with the special @null value -- it turns back to TYPE_NULL.
1111 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001112 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001114 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001117 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1118 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119
1120 // Write the final value back to Java.
1121 dest[STYLE_TYPE] = value.dataType;
1122 dest[STYLE_DATA] = value.data;
1123 dest[STYLE_ASSET_COOKIE] =
1124 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1125 dest[STYLE_RESOURCE_ID] = resid;
1126 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001127 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128
1129 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1130 indicesIdx++;
1131 indices[indicesIdx] = ii;
1132 }
1133
1134 dest += STYLE_NUM_ENTRIES;
1135 }
1136
1137 res.unlock();
1138
1139 if (indices != NULL) {
1140 indices[0] = indicesIdx;
1141 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1142 }
1143 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1144 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1145
1146 return JNI_TRUE;
1147}
1148
1149static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1150 jint xmlParserToken,
1151 jintArray attrs,
1152 jintArray outValues,
1153 jintArray outIndices)
1154{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001155 if (xmlParserToken == 0) {
1156 jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
1157 return JNI_FALSE;
1158 }
1159 if (attrs == NULL) {
1160 jniThrowException(env, "java/lang/NullPointerException", "attrs");
1161 return JNI_FALSE;
1162 }
1163 if (outValues == NULL) {
1164 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 return JNI_FALSE;
1166 }
1167
1168 AssetManager* am = assetManagerForJavaObject(env, clazz);
1169 if (am == NULL) {
1170 return JNI_FALSE;
1171 }
1172 const ResTable& res(am->getResources());
1173 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001174 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 Res_value value;
1176
1177 const jsize NI = env->GetArrayLength(attrs);
1178 const jsize NV = env->GetArrayLength(outValues);
1179 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001180 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 return JNI_FALSE;
1182 }
1183
1184 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1185 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001186 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 return JNI_FALSE;
1188 }
1189
1190 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1191 jint* dest = baseDest;
1192 if (dest == NULL) {
1193 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001194 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 return JNI_FALSE;
1196 }
1197
1198 jint* indices = NULL;
1199 int indicesIdx = 0;
1200 if (outIndices != NULL) {
1201 if (env->GetArrayLength(outIndices) > NI) {
1202 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1203 }
1204 }
1205
1206 // Now lock down the resource object and start pulling stuff from it.
1207 res.lock();
1208
1209 // Retrieve the XML attributes, if requested.
1210 const jsize NX = xmlParser->getAttributeCount();
1211 jsize ix=0;
1212 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1213
1214 static const ssize_t kXmlBlock = 0x10000000;
1215
1216 // Now iterate through all of the attributes that the client has requested,
1217 // filling in each with whatever data we can find.
1218 ssize_t block = 0;
1219 uint32_t typeSetFlags;
1220 for (jsize ii=0; ii<NI; ii++) {
1221 const uint32_t curIdent = (uint32_t)src[ii];
1222
1223 // Try to find a value for this attribute...
1224 value.dataType = Res_value::TYPE_NULL;
1225 value.data = 0;
1226 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001227 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228
1229 // Skip through XML attributes until the end or the next possible match.
1230 while (ix < NX && curIdent > curXmlAttr) {
1231 ix++;
1232 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1233 }
1234 // Retrieve the current XML attribute if it matches, and step to next.
1235 if (ix < NX && curIdent == curXmlAttr) {
1236 block = kXmlBlock;
1237 xmlParser->getAttributeValue(ix, &value);
1238 ix++;
1239 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1240 }
1241
1242 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1243 uint32_t resid = 0;
1244 if (value.dataType != Res_value::TYPE_NULL) {
1245 // Take care of resolving the found resource to its final value.
1246 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001247 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1248 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001249#if THROW_ON_BAD_ID
1250 if (newBlock == BAD_INDEX) {
1251 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1252 return JNI_FALSE;
1253 }
1254#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 if (newBlock >= 0) block = newBlock;
1256 }
1257
1258 // Deal with the special @null value -- it turns back to TYPE_NULL.
1259 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1260 value.dataType = Res_value::TYPE_NULL;
1261 }
1262
1263 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1264
1265 // Write the final value back to Java.
1266 dest[STYLE_TYPE] = value.dataType;
1267 dest[STYLE_DATA] = value.data;
1268 dest[STYLE_ASSET_COOKIE] =
1269 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1270 dest[STYLE_RESOURCE_ID] = resid;
1271 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001272 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273
1274 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1275 indicesIdx++;
1276 indices[indicesIdx] = ii;
1277 }
1278
1279 dest += STYLE_NUM_ENTRIES;
1280 }
1281
1282 res.unlock();
1283
1284 if (indices != NULL) {
1285 indices[0] = indicesIdx;
1286 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1287 }
1288
1289 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1290 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1291
1292 return JNI_TRUE;
1293}
1294
1295static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1296 jint id)
1297{
1298 AssetManager* am = assetManagerForJavaObject(env, clazz);
1299 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001300 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302 const ResTable& res(am->getResources());
1303
1304 res.lock();
1305 const ResTable::bag_entry* defStyleEnt = NULL;
1306 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1307 res.unlock();
1308
1309 return bagOff;
1310}
1311
1312static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1313 jint id,
1314 jintArray outValues)
1315{
1316 if (outValues == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001317 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 return JNI_FALSE;
1319 }
1320
1321 AssetManager* am = assetManagerForJavaObject(env, clazz);
1322 if (am == NULL) {
1323 return JNI_FALSE;
1324 }
1325 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001326 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 Res_value value;
1328 ssize_t block;
1329
1330 const jsize NV = env->GetArrayLength(outValues);
1331
1332 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1333 jint* dest = baseDest;
1334 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001335 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 return JNI_FALSE;
1337 }
1338
1339 // Now lock down the resource object and start pulling stuff from it.
1340 res.lock();
1341
1342 const ResTable::bag_entry* arrayEnt = NULL;
1343 uint32_t arrayTypeSetFlags = 0;
1344 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1345 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1346 (bagOff >= 0 ? bagOff : 0);
1347
1348 int i = 0;
1349 uint32_t typeSetFlags;
1350 while (i < NV && arrayEnt < endArrayEnt) {
1351 block = arrayEnt->stringBlock;
1352 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001353 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 value = arrayEnt->map.value;
1355
1356 uint32_t resid = 0;
1357 if (value.dataType != Res_value::TYPE_NULL) {
1358 // Take care of resolving the found resource to its final value.
1359 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001360 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1361 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001362#if THROW_ON_BAD_ID
1363 if (newBlock == BAD_INDEX) {
1364 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1365 return JNI_FALSE;
1366 }
1367#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 if (newBlock >= 0) block = newBlock;
1369 }
1370
1371 // Deal with the special @null value -- it turns back to TYPE_NULL.
1372 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1373 value.dataType = Res_value::TYPE_NULL;
1374 }
1375
1376 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1377
1378 // Write the final value back to Java.
1379 dest[STYLE_TYPE] = value.dataType;
1380 dest[STYLE_DATA] = value.data;
1381 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1382 dest[STYLE_RESOURCE_ID] = resid;
1383 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001384 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 dest += STYLE_NUM_ENTRIES;
1386 i+= STYLE_NUM_ENTRIES;
1387 arrayEnt++;
1388 }
1389
1390 i /= STYLE_NUM_ENTRIES;
1391
1392 res.unlock();
1393
1394 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1395
1396 return i;
1397}
1398
1399static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1400 jint cookie,
1401 jstring fileName)
1402{
1403 AssetManager* am = assetManagerForJavaObject(env, clazz);
1404 if (am == NULL) {
1405 return 0;
1406 }
1407
1408 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1409
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001410 if (fileName == NULL) {
1411 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 return 0;
1413 }
1414
1415 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1416 Asset* a = cookie
1417 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1418 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1419
1420 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001421 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 env->ReleaseStringUTFChars(fileName, fileName8);
1423 return 0;
1424 }
1425 env->ReleaseStringUTFChars(fileName, fileName8);
1426
1427 ResXMLTree* block = new ResXMLTree();
1428 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1429 a->close();
1430 delete a;
1431
1432 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001433 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 return 0;
1435 }
1436
1437 return (jint)block;
1438}
1439
1440static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1441 jint arrayResId)
1442{
1443 AssetManager* am = assetManagerForJavaObject(env, clazz);
1444 if (am == NULL) {
1445 return NULL;
1446 }
1447 const ResTable& res(am->getResources());
1448
1449 const ResTable::bag_entry* startOfBag;
1450 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1451 if (N < 0) {
1452 return NULL;
1453 }
1454
1455 jintArray array = env->NewIntArray(N * 2);
1456 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001457 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 res.unlockBag(startOfBag);
1459 return NULL;
1460 }
1461
1462 Res_value value;
1463 const ResTable::bag_entry* bag = startOfBag;
1464 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1465 jint stringIndex = -1;
1466 jint stringBlock = 0;
1467 value = bag->map.value;
1468
1469 // Take care of resolving the found resource to its final value.
1470 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1471 if (value.dataType == Res_value::TYPE_STRING) {
1472 stringIndex = value.data;
1473 }
1474
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001475#if THROW_ON_BAD_ID
1476 if (stringBlock == BAD_INDEX) {
1477 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1478 return array;
1479 }
1480#endif
1481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 //todo: It might be faster to allocate a C array to contain
1483 // the blocknums and indices, put them in there and then
1484 // do just one SetIntArrayRegion()
1485 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1486 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1487 j = j + 2;
1488 }
1489 res.unlockBag(startOfBag);
1490 return array;
1491}
1492
1493static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1494 jint arrayResId)
1495{
1496 AssetManager* am = assetManagerForJavaObject(env, clazz);
1497 if (am == NULL) {
1498 return NULL;
1499 }
1500 const ResTable& res(am->getResources());
1501
1502 jclass cls = env->FindClass("java/lang/String");
1503 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1504 if (cls == NULL) {
1505 return NULL;
1506 }
1507
1508 const ResTable::bag_entry* startOfBag;
1509 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1510 if (N < 0) {
1511 return NULL;
1512 }
1513
1514 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001515 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 res.unlockBag(startOfBag);
1517 return NULL;
1518 }
1519
1520 Res_value value;
1521 const ResTable::bag_entry* bag = startOfBag;
1522 size_t strLen = 0;
1523 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1524 value = bag->map.value;
1525 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 // Take care of resolving the found resource to its final value.
1528 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001529#if THROW_ON_BAD_ID
1530 if (block == BAD_INDEX) {
1531 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1532 return array;
1533 }
1534#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001536 const ResStringPool* pool = res.getTableStringBlock(block);
1537 const char* str8 = pool->string8At(value.data, &strLen);
1538 if (str8 != NULL) {
1539 str = env->NewStringUTF(str8);
1540 } else {
1541 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1542 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001543 }
1544
1545 // If one of our NewString{UTF} calls failed due to memory, an
1546 // exception will be pending.
1547 if (env->ExceptionCheck()) {
1548 res.unlockBag(startOfBag);
1549 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
Kenny Root780d2a12010-02-22 22:36:26 -08001551
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001552 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001553
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001554 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1555 // If we have a large amount of strings in our array, we might
1556 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001557 env->DeleteLocalRef(str);
1558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 }
1560 res.unlockBag(startOfBag);
1561 return array;
1562}
1563
1564static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1565 jint arrayResId)
1566{
1567 AssetManager* am = assetManagerForJavaObject(env, clazz);
1568 if (am == NULL) {
1569 return NULL;
1570 }
1571 const ResTable& res(am->getResources());
1572
1573 const ResTable::bag_entry* startOfBag;
1574 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1575 if (N < 0) {
1576 return NULL;
1577 }
1578
1579 jintArray array = env->NewIntArray(N);
1580 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001581 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 res.unlockBag(startOfBag);
1583 return NULL;
1584 }
1585
1586 Res_value value;
1587 const ResTable::bag_entry* bag = startOfBag;
1588 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1589 value = bag->map.value;
1590
1591 // Take care of resolving the found resource to its final value.
1592 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001593#if THROW_ON_BAD_ID
1594 if (block == BAD_INDEX) {
1595 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1596 return array;
1597 }
1598#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 if (value.dataType >= Res_value::TYPE_FIRST_INT
1600 && value.dataType <= Res_value::TYPE_LAST_INT) {
1601 int intVal = value.data;
1602 env->SetIntArrayRegion(array, i, 1, &intVal);
1603 }
1604 }
1605 res.unlockBag(startOfBag);
1606 return array;
1607}
1608
1609static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1610{
1611 AssetManager* am = new AssetManager();
1612 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001613 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 return;
1615 }
1616
1617 am->addDefaultAssets();
1618
1619 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1620 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1621}
1622
1623static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1624{
1625 AssetManager* am = (AssetManager*)
1626 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1627 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1628 if (am != NULL) {
1629 delete am;
1630 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1631 }
1632}
1633
1634static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1635{
1636 return Asset::getGlobalCount();
1637}
1638
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001639static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1640{
1641 String8 alloc = Asset::getAssetAllocations();
1642 if (alloc.length() <= 0) {
1643 return NULL;
1644 }
1645
1646 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001647 return str;
1648}
1649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1651{
1652 return AssetManager::getGlobalCount();
1653}
1654
1655// ----------------------------------------------------------------------------
1656
1657/*
1658 * JNI registration.
1659 */
1660static JNINativeMethod gAssetManagerMethods[] = {
1661 /* name, signature, funcPtr */
1662
1663 // Basic asset stuff.
1664 { "openAsset", "(Ljava/lang/String;I)I",
1665 (void*) android_content_AssetManager_openAsset },
1666 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1667 (void*) android_content_AssetManager_openAssetFd },
1668 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1669 (void*) android_content_AssetManager_openNonAssetNative },
1670 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1671 (void*) android_content_AssetManager_openNonAssetFdNative },
1672 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1673 (void*) android_content_AssetManager_list },
1674 { "destroyAsset", "(I)V",
1675 (void*) android_content_AssetManager_destroyAsset },
1676 { "readAssetChar", "(I)I",
1677 (void*) android_content_AssetManager_readAssetChar },
1678 { "readAsset", "(I[BII)I",
1679 (void*) android_content_AssetManager_readAsset },
1680 { "seekAsset", "(IJI)J",
1681 (void*) android_content_AssetManager_seekAsset },
1682 { "getAssetLength", "(I)J",
1683 (void*) android_content_AssetManager_getAssetLength },
1684 { "getAssetRemainingLength", "(I)J",
1685 (void*) android_content_AssetManager_getAssetRemainingLength },
1686 { "addAssetPath", "(Ljava/lang/String;)I",
1687 (void*) android_content_AssetManager_addAssetPath },
1688 { "isUpToDate", "()Z",
1689 (void*) android_content_AssetManager_isUpToDate },
1690
1691 // Resources.
1692 { "setLocale", "(Ljava/lang/String;)V",
1693 (void*) android_content_AssetManager_setLocale },
1694 { "getLocales", "()[Ljava/lang/String;",
1695 (void*) android_content_AssetManager_getLocales },
Tobias Haamel27b28b32010-02-09 23:09:17 +01001696 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 (void*) android_content_AssetManager_setConfiguration },
1698 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1699 (void*) android_content_AssetManager_getResourceIdentifier },
1700 { "getResourceName","(I)Ljava/lang/String;",
1701 (void*) android_content_AssetManager_getResourceName },
1702 { "getResourcePackageName","(I)Ljava/lang/String;",
1703 (void*) android_content_AssetManager_getResourcePackageName },
1704 { "getResourceTypeName","(I)Ljava/lang/String;",
1705 (void*) android_content_AssetManager_getResourceTypeName },
1706 { "getResourceEntryName","(I)Ljava/lang/String;",
1707 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001708 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 (void*) android_content_AssetManager_loadResourceValue },
1710 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1711 (void*) android_content_AssetManager_loadResourceBagValue },
1712 { "getStringBlockCount","()I",
1713 (void*) android_content_AssetManager_getStringBlockCount },
1714 { "getNativeStringBlock","(I)I",
1715 (void*) android_content_AssetManager_getNativeStringBlock },
1716 { "getCookieName","(I)Ljava/lang/String;",
1717 (void*) android_content_AssetManager_getCookieName },
1718
1719 // Themes.
1720 { "newTheme", "()I",
1721 (void*) android_content_AssetManager_newTheme },
1722 { "deleteTheme", "(I)V",
1723 (void*) android_content_AssetManager_deleteTheme },
1724 { "applyThemeStyle", "(IIZ)V",
1725 (void*) android_content_AssetManager_applyThemeStyle },
1726 { "copyTheme", "(II)V",
1727 (void*) android_content_AssetManager_copyTheme },
1728 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1729 (void*) android_content_AssetManager_loadThemeAttributeValue },
1730 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1731 (void*) android_content_AssetManager_dumpTheme },
1732 { "applyStyle","(IIII[I[I[I)Z",
1733 (void*) android_content_AssetManager_applyStyle },
1734 { "retrieveAttributes","(I[I[I[I)Z",
1735 (void*) android_content_AssetManager_retrieveAttributes },
1736 { "getArraySize","(I)I",
1737 (void*) android_content_AssetManager_getArraySize },
1738 { "retrieveArray","(I[I)I",
1739 (void*) android_content_AssetManager_retrieveArray },
1740
1741 // XML files.
1742 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1743 (void*) android_content_AssetManager_openXmlAssetNative },
1744
1745 // Arrays.
1746 { "getArrayStringResource","(I)[Ljava/lang/String;",
1747 (void*) android_content_AssetManager_getArrayStringResource },
1748 { "getArrayStringInfo","(I)[I",
1749 (void*) android_content_AssetManager_getArrayStringInfo },
1750 { "getArrayIntResource","(I)[I",
1751 (void*) android_content_AssetManager_getArrayIntResource },
1752
1753 // Bookkeeping.
1754 { "init", "()V",
1755 (void*) android_content_AssetManager_init },
1756 { "destroy", "()V",
1757 (void*) android_content_AssetManager_destroy },
1758 { "getGlobalAssetCount", "()I",
1759 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001760 { "getAssetAllocations", "()Ljava/lang/String;",
1761 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 { "getGlobalAssetManagerCount", "()I",
1763 (void*) android_content_AssetManager_getGlobalAssetCount },
1764};
1765
1766int register_android_content_AssetManager(JNIEnv* env)
1767{
1768 jclass typedValue = env->FindClass("android/util/TypedValue");
1769 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1770 gTypedValueOffsets.mType
1771 = env->GetFieldID(typedValue, "type", "I");
1772 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1773 gTypedValueOffsets.mData
1774 = env->GetFieldID(typedValue, "data", "I");
1775 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1776 gTypedValueOffsets.mString
1777 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1778 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1779 gTypedValueOffsets.mAssetCookie
1780 = env->GetFieldID(typedValue, "assetCookie", "I");
1781 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1782 gTypedValueOffsets.mResourceId
1783 = env->GetFieldID(typedValue, "resourceId", "I");
1784 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1785 gTypedValueOffsets.mChangingConfigurations
1786 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1787 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1788 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1789 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1790
1791 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1792 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1793 gAssetFileDescriptorOffsets.mFd
1794 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1795 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1796 gAssetFileDescriptorOffsets.mStartOffset
1797 = env->GetFieldID(assetFd, "mStartOffset", "J");
1798 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1799 gAssetFileDescriptorOffsets.mLength
1800 = env->GetFieldID(assetFd, "mLength", "J");
1801 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1802
1803 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1804 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1805 gAssetManagerOffsets.mObject
1806 = env->GetFieldID(assetManager, "mObject", "I");
1807 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1808
1809 g_stringClass = env->FindClass("java/lang/String");
1810
1811 return AndroidRuntime::registerNativeMethods(env,
1812 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1813}
1814
1815}; // namespace android