blob: 619a2939567575d7d1ea57850d133b2807b25212 [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;
1114 }
1115
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001116 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1117 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118
1119 // Write the final value back to Java.
1120 dest[STYLE_TYPE] = value.dataType;
1121 dest[STYLE_DATA] = value.data;
1122 dest[STYLE_ASSET_COOKIE] =
1123 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1124 dest[STYLE_RESOURCE_ID] = resid;
1125 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001126 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127
1128 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1129 indicesIdx++;
1130 indices[indicesIdx] = ii;
1131 }
1132
1133 dest += STYLE_NUM_ENTRIES;
1134 }
1135
1136 res.unlock();
1137
1138 if (indices != NULL) {
1139 indices[0] = indicesIdx;
1140 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1141 }
1142 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1143 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1144
1145 return JNI_TRUE;
1146}
1147
1148static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1149 jint xmlParserToken,
1150 jintArray attrs,
1151 jintArray outValues,
1152 jintArray outIndices)
1153{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001154 if (xmlParserToken == 0) {
1155 jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
1156 return JNI_FALSE;
1157 }
1158 if (attrs == NULL) {
1159 jniThrowException(env, "java/lang/NullPointerException", "attrs");
1160 return JNI_FALSE;
1161 }
1162 if (outValues == NULL) {
1163 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 return JNI_FALSE;
1165 }
1166
1167 AssetManager* am = assetManagerForJavaObject(env, clazz);
1168 if (am == NULL) {
1169 return JNI_FALSE;
1170 }
1171 const ResTable& res(am->getResources());
1172 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001173 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 Res_value value;
1175
1176 const jsize NI = env->GetArrayLength(attrs);
1177 const jsize NV = env->GetArrayLength(outValues);
1178 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001179 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 return JNI_FALSE;
1181 }
1182
1183 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1184 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001185 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 return JNI_FALSE;
1187 }
1188
1189 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1190 jint* dest = baseDest;
1191 if (dest == NULL) {
1192 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001193 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 return JNI_FALSE;
1195 }
1196
1197 jint* indices = NULL;
1198 int indicesIdx = 0;
1199 if (outIndices != NULL) {
1200 if (env->GetArrayLength(outIndices) > NI) {
1201 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1202 }
1203 }
1204
1205 // Now lock down the resource object and start pulling stuff from it.
1206 res.lock();
1207
1208 // Retrieve the XML attributes, if requested.
1209 const jsize NX = xmlParser->getAttributeCount();
1210 jsize ix=0;
1211 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1212
1213 static const ssize_t kXmlBlock = 0x10000000;
1214
1215 // Now iterate through all of the attributes that the client has requested,
1216 // filling in each with whatever data we can find.
1217 ssize_t block = 0;
1218 uint32_t typeSetFlags;
1219 for (jsize ii=0; ii<NI; ii++) {
1220 const uint32_t curIdent = (uint32_t)src[ii];
1221
1222 // Try to find a value for this attribute...
1223 value.dataType = Res_value::TYPE_NULL;
1224 value.data = 0;
1225 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001226 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227
1228 // Skip through XML attributes until the end or the next possible match.
1229 while (ix < NX && curIdent > curXmlAttr) {
1230 ix++;
1231 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1232 }
1233 // Retrieve the current XML attribute if it matches, and step to next.
1234 if (ix < NX && curIdent == curXmlAttr) {
1235 block = kXmlBlock;
1236 xmlParser->getAttributeValue(ix, &value);
1237 ix++;
1238 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1239 }
1240
1241 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1242 uint32_t resid = 0;
1243 if (value.dataType != Res_value::TYPE_NULL) {
1244 // Take care of resolving the found resource to its final value.
1245 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001246 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1247 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001248#if THROW_ON_BAD_ID
1249 if (newBlock == BAD_INDEX) {
1250 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1251 return JNI_FALSE;
1252 }
1253#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 if (newBlock >= 0) block = newBlock;
1255 }
1256
1257 // Deal with the special @null value -- it turns back to TYPE_NULL.
1258 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1259 value.dataType = Res_value::TYPE_NULL;
1260 }
1261
1262 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1263
1264 // Write the final value back to Java.
1265 dest[STYLE_TYPE] = value.dataType;
1266 dest[STYLE_DATA] = value.data;
1267 dest[STYLE_ASSET_COOKIE] =
1268 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1269 dest[STYLE_RESOURCE_ID] = resid;
1270 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001271 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272
1273 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1274 indicesIdx++;
1275 indices[indicesIdx] = ii;
1276 }
1277
1278 dest += STYLE_NUM_ENTRIES;
1279 }
1280
1281 res.unlock();
1282
1283 if (indices != NULL) {
1284 indices[0] = indicesIdx;
1285 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1286 }
1287
1288 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1289 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1290
1291 return JNI_TRUE;
1292}
1293
1294static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1295 jint id)
1296{
1297 AssetManager* am = assetManagerForJavaObject(env, clazz);
1298 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001299 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 }
1301 const ResTable& res(am->getResources());
1302
1303 res.lock();
1304 const ResTable::bag_entry* defStyleEnt = NULL;
1305 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1306 res.unlock();
1307
1308 return bagOff;
1309}
1310
1311static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1312 jint id,
1313 jintArray outValues)
1314{
1315 if (outValues == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001316 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 return JNI_FALSE;
1318 }
1319
1320 AssetManager* am = assetManagerForJavaObject(env, clazz);
1321 if (am == NULL) {
1322 return JNI_FALSE;
1323 }
1324 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001325 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 Res_value value;
1327 ssize_t block;
1328
1329 const jsize NV = env->GetArrayLength(outValues);
1330
1331 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1332 jint* dest = baseDest;
1333 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001334 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 return JNI_FALSE;
1336 }
1337
1338 // Now lock down the resource object and start pulling stuff from it.
1339 res.lock();
1340
1341 const ResTable::bag_entry* arrayEnt = NULL;
1342 uint32_t arrayTypeSetFlags = 0;
1343 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1344 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1345 (bagOff >= 0 ? bagOff : 0);
1346
1347 int i = 0;
1348 uint32_t typeSetFlags;
1349 while (i < NV && arrayEnt < endArrayEnt) {
1350 block = arrayEnt->stringBlock;
1351 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001352 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 value = arrayEnt->map.value;
1354
1355 uint32_t resid = 0;
1356 if (value.dataType != Res_value::TYPE_NULL) {
1357 // Take care of resolving the found resource to its final value.
1358 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001359 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1360 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001361#if THROW_ON_BAD_ID
1362 if (newBlock == BAD_INDEX) {
1363 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1364 return JNI_FALSE;
1365 }
1366#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 if (newBlock >= 0) block = newBlock;
1368 }
1369
1370 // Deal with the special @null value -- it turns back to TYPE_NULL.
1371 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1372 value.dataType = Res_value::TYPE_NULL;
1373 }
1374
1375 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1376
1377 // Write the final value back to Java.
1378 dest[STYLE_TYPE] = value.dataType;
1379 dest[STYLE_DATA] = value.data;
1380 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1381 dest[STYLE_RESOURCE_ID] = resid;
1382 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001383 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 dest += STYLE_NUM_ENTRIES;
1385 i+= STYLE_NUM_ENTRIES;
1386 arrayEnt++;
1387 }
1388
1389 i /= STYLE_NUM_ENTRIES;
1390
1391 res.unlock();
1392
1393 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1394
1395 return i;
1396}
1397
1398static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1399 jint cookie,
1400 jstring fileName)
1401{
1402 AssetManager* am = assetManagerForJavaObject(env, clazz);
1403 if (am == NULL) {
1404 return 0;
1405 }
1406
1407 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1408
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001409 if (fileName == NULL) {
1410 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 return 0;
1412 }
1413
1414 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1415 Asset* a = cookie
1416 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1417 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1418
1419 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001420 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 env->ReleaseStringUTFChars(fileName, fileName8);
1422 return 0;
1423 }
1424 env->ReleaseStringUTFChars(fileName, fileName8);
1425
1426 ResXMLTree* block = new ResXMLTree();
1427 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1428 a->close();
1429 delete a;
1430
1431 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001432 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 return 0;
1434 }
1435
1436 return (jint)block;
1437}
1438
1439static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1440 jint arrayResId)
1441{
1442 AssetManager* am = assetManagerForJavaObject(env, clazz);
1443 if (am == NULL) {
1444 return NULL;
1445 }
1446 const ResTable& res(am->getResources());
1447
1448 const ResTable::bag_entry* startOfBag;
1449 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1450 if (N < 0) {
1451 return NULL;
1452 }
1453
1454 jintArray array = env->NewIntArray(N * 2);
1455 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001456 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 res.unlockBag(startOfBag);
1458 return NULL;
1459 }
1460
1461 Res_value value;
1462 const ResTable::bag_entry* bag = startOfBag;
1463 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1464 jint stringIndex = -1;
1465 jint stringBlock = 0;
1466 value = bag->map.value;
1467
1468 // Take care of resolving the found resource to its final value.
1469 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1470 if (value.dataType == Res_value::TYPE_STRING) {
1471 stringIndex = value.data;
1472 }
1473
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001474#if THROW_ON_BAD_ID
1475 if (stringBlock == BAD_INDEX) {
1476 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1477 return array;
1478 }
1479#endif
1480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 //todo: It might be faster to allocate a C array to contain
1482 // the blocknums and indices, put them in there and then
1483 // do just one SetIntArrayRegion()
1484 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1485 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1486 j = j + 2;
1487 }
1488 res.unlockBag(startOfBag);
1489 return array;
1490}
1491
1492static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1493 jint arrayResId)
1494{
1495 AssetManager* am = assetManagerForJavaObject(env, clazz);
1496 if (am == NULL) {
1497 return NULL;
1498 }
1499 const ResTable& res(am->getResources());
1500
1501 jclass cls = env->FindClass("java/lang/String");
1502 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1503 if (cls == NULL) {
1504 return NULL;
1505 }
1506
1507 const ResTable::bag_entry* startOfBag;
1508 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1509 if (N < 0) {
1510 return NULL;
1511 }
1512
1513 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001514 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 res.unlockBag(startOfBag);
1516 return NULL;
1517 }
1518
1519 Res_value value;
1520 const ResTable::bag_entry* bag = startOfBag;
1521 size_t strLen = 0;
1522 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1523 value = bag->map.value;
1524 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 // Take care of resolving the found resource to its final value.
1527 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001528#if THROW_ON_BAD_ID
1529 if (block == BAD_INDEX) {
1530 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1531 return array;
1532 }
1533#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001535 const ResStringPool* pool = res.getTableStringBlock(block);
1536 const char* str8 = pool->string8At(value.data, &strLen);
1537 if (str8 != NULL) {
1538 str = env->NewStringUTF(str8);
1539 } else {
1540 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1541 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001542 }
1543
1544 // If one of our NewString{UTF} calls failed due to memory, an
1545 // exception will be pending.
1546 if (env->ExceptionCheck()) {
1547 res.unlockBag(startOfBag);
1548 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 }
Kenny Root780d2a12010-02-22 22:36:26 -08001550
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001551 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001552
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001553 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1554 // If we have a large amount of strings in our array, we might
1555 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001556 env->DeleteLocalRef(str);
1557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
1559 res.unlockBag(startOfBag);
1560 return array;
1561}
1562
1563static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1564 jint arrayResId)
1565{
1566 AssetManager* am = assetManagerForJavaObject(env, clazz);
1567 if (am == NULL) {
1568 return NULL;
1569 }
1570 const ResTable& res(am->getResources());
1571
1572 const ResTable::bag_entry* startOfBag;
1573 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1574 if (N < 0) {
1575 return NULL;
1576 }
1577
1578 jintArray array = env->NewIntArray(N);
1579 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001580 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 res.unlockBag(startOfBag);
1582 return NULL;
1583 }
1584
1585 Res_value value;
1586 const ResTable::bag_entry* bag = startOfBag;
1587 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1588 value = bag->map.value;
1589
1590 // Take care of resolving the found resource to its final value.
1591 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001592#if THROW_ON_BAD_ID
1593 if (block == BAD_INDEX) {
1594 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1595 return array;
1596 }
1597#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 if (value.dataType >= Res_value::TYPE_FIRST_INT
1599 && value.dataType <= Res_value::TYPE_LAST_INT) {
1600 int intVal = value.data;
1601 env->SetIntArrayRegion(array, i, 1, &intVal);
1602 }
1603 }
1604 res.unlockBag(startOfBag);
1605 return array;
1606}
1607
1608static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1609{
1610 AssetManager* am = new AssetManager();
1611 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001612 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 return;
1614 }
1615
1616 am->addDefaultAssets();
1617
1618 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1619 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1620}
1621
1622static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1623{
1624 AssetManager* am = (AssetManager*)
1625 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1626 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1627 if (am != NULL) {
1628 delete am;
1629 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1630 }
1631}
1632
1633static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1634{
1635 return Asset::getGlobalCount();
1636}
1637
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001638static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1639{
1640 String8 alloc = Asset::getAssetAllocations();
1641 if (alloc.length() <= 0) {
1642 return NULL;
1643 }
1644
1645 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001646 return str;
1647}
1648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1650{
1651 return AssetManager::getGlobalCount();
1652}
1653
1654// ----------------------------------------------------------------------------
1655
1656/*
1657 * JNI registration.
1658 */
1659static JNINativeMethod gAssetManagerMethods[] = {
1660 /* name, signature, funcPtr */
1661
1662 // Basic asset stuff.
1663 { "openAsset", "(Ljava/lang/String;I)I",
1664 (void*) android_content_AssetManager_openAsset },
1665 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1666 (void*) android_content_AssetManager_openAssetFd },
1667 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1668 (void*) android_content_AssetManager_openNonAssetNative },
1669 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1670 (void*) android_content_AssetManager_openNonAssetFdNative },
1671 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1672 (void*) android_content_AssetManager_list },
1673 { "destroyAsset", "(I)V",
1674 (void*) android_content_AssetManager_destroyAsset },
1675 { "readAssetChar", "(I)I",
1676 (void*) android_content_AssetManager_readAssetChar },
1677 { "readAsset", "(I[BII)I",
1678 (void*) android_content_AssetManager_readAsset },
1679 { "seekAsset", "(IJI)J",
1680 (void*) android_content_AssetManager_seekAsset },
1681 { "getAssetLength", "(I)J",
1682 (void*) android_content_AssetManager_getAssetLength },
1683 { "getAssetRemainingLength", "(I)J",
1684 (void*) android_content_AssetManager_getAssetRemainingLength },
1685 { "addAssetPath", "(Ljava/lang/String;)I",
1686 (void*) android_content_AssetManager_addAssetPath },
1687 { "isUpToDate", "()Z",
1688 (void*) android_content_AssetManager_isUpToDate },
1689
1690 // Resources.
1691 { "setLocale", "(Ljava/lang/String;)V",
1692 (void*) android_content_AssetManager_setLocale },
1693 { "getLocales", "()[Ljava/lang/String;",
1694 (void*) android_content_AssetManager_getLocales },
Tobias Haamel27b28b32010-02-09 23:09:17 +01001695 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 (void*) android_content_AssetManager_setConfiguration },
1697 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1698 (void*) android_content_AssetManager_getResourceIdentifier },
1699 { "getResourceName","(I)Ljava/lang/String;",
1700 (void*) android_content_AssetManager_getResourceName },
1701 { "getResourcePackageName","(I)Ljava/lang/String;",
1702 (void*) android_content_AssetManager_getResourcePackageName },
1703 { "getResourceTypeName","(I)Ljava/lang/String;",
1704 (void*) android_content_AssetManager_getResourceTypeName },
1705 { "getResourceEntryName","(I)Ljava/lang/String;",
1706 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001707 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 (void*) android_content_AssetManager_loadResourceValue },
1709 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1710 (void*) android_content_AssetManager_loadResourceBagValue },
1711 { "getStringBlockCount","()I",
1712 (void*) android_content_AssetManager_getStringBlockCount },
1713 { "getNativeStringBlock","(I)I",
1714 (void*) android_content_AssetManager_getNativeStringBlock },
1715 { "getCookieName","(I)Ljava/lang/String;",
1716 (void*) android_content_AssetManager_getCookieName },
1717
1718 // Themes.
1719 { "newTheme", "()I",
1720 (void*) android_content_AssetManager_newTheme },
1721 { "deleteTheme", "(I)V",
1722 (void*) android_content_AssetManager_deleteTheme },
1723 { "applyThemeStyle", "(IIZ)V",
1724 (void*) android_content_AssetManager_applyThemeStyle },
1725 { "copyTheme", "(II)V",
1726 (void*) android_content_AssetManager_copyTheme },
1727 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1728 (void*) android_content_AssetManager_loadThemeAttributeValue },
1729 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1730 (void*) android_content_AssetManager_dumpTheme },
1731 { "applyStyle","(IIII[I[I[I)Z",
1732 (void*) android_content_AssetManager_applyStyle },
1733 { "retrieveAttributes","(I[I[I[I)Z",
1734 (void*) android_content_AssetManager_retrieveAttributes },
1735 { "getArraySize","(I)I",
1736 (void*) android_content_AssetManager_getArraySize },
1737 { "retrieveArray","(I[I)I",
1738 (void*) android_content_AssetManager_retrieveArray },
1739
1740 // XML files.
1741 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1742 (void*) android_content_AssetManager_openXmlAssetNative },
1743
1744 // Arrays.
1745 { "getArrayStringResource","(I)[Ljava/lang/String;",
1746 (void*) android_content_AssetManager_getArrayStringResource },
1747 { "getArrayStringInfo","(I)[I",
1748 (void*) android_content_AssetManager_getArrayStringInfo },
1749 { "getArrayIntResource","(I)[I",
1750 (void*) android_content_AssetManager_getArrayIntResource },
1751
1752 // Bookkeeping.
1753 { "init", "()V",
1754 (void*) android_content_AssetManager_init },
1755 { "destroy", "()V",
1756 (void*) android_content_AssetManager_destroy },
1757 { "getGlobalAssetCount", "()I",
1758 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001759 { "getAssetAllocations", "()Ljava/lang/String;",
1760 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 { "getGlobalAssetManagerCount", "()I",
1762 (void*) android_content_AssetManager_getGlobalAssetCount },
1763};
1764
1765int register_android_content_AssetManager(JNIEnv* env)
1766{
1767 jclass typedValue = env->FindClass("android/util/TypedValue");
1768 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1769 gTypedValueOffsets.mType
1770 = env->GetFieldID(typedValue, "type", "I");
1771 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1772 gTypedValueOffsets.mData
1773 = env->GetFieldID(typedValue, "data", "I");
1774 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1775 gTypedValueOffsets.mString
1776 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1777 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1778 gTypedValueOffsets.mAssetCookie
1779 = env->GetFieldID(typedValue, "assetCookie", "I");
1780 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1781 gTypedValueOffsets.mResourceId
1782 = env->GetFieldID(typedValue, "resourceId", "I");
1783 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1784 gTypedValueOffsets.mChangingConfigurations
1785 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1786 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1787 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1788 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1789
1790 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1791 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1792 gAssetFileDescriptorOffsets.mFd
1793 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1794 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1795 gAssetFileDescriptorOffsets.mStartOffset
1796 = env->GetFieldID(assetFd, "mStartOffset", "J");
1797 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1798 gAssetFileDescriptorOffsets.mLength
1799 = env->GetFieldID(assetFd, "mLength", "J");
1800 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1801
1802 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1803 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1804 gAssetManagerOffsets.mObject
1805 = env->GetFieldID(assetManager, "mObject", "I");
1806 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1807
1808 g_stringClass = env->FindClass("java/lang/String");
1809
1810 return AndroidRuntime::registerNativeMethods(env,
1811 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1812}
1813
1814}; // namespace android