blob: 636d257f987f5f9fbd9f516a3c31da6628329601 [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,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700535 jint smallestScreenWidthDp,
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700536 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100537 jint screenLayout, jint uiMode,
538 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539{
540 AssetManager* am = assetManagerForJavaObject(env, clazz);
541 if (am == NULL) {
542 return;
543 }
544
545 ResTable_config config;
546 memset(&config, 0, sizeof(config));
547
548 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
549
550 config.mcc = (uint16_t)mcc;
551 config.mnc = (uint16_t)mnc;
552 config.orientation = (uint8_t)orientation;
553 config.touchscreen = (uint8_t)touchscreen;
554 config.density = (uint16_t)density;
555 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700556 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 config.navigation = (uint8_t)navigation;
558 config.screenWidth = (uint16_t)screenWidth;
559 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700560 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700561 config.screenWidthDp = (uint16_t)screenWidthDp;
562 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700563 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100564 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 config.sdkVersion = (uint16_t)sdkVersion;
566 config.minorVersion = 0;
567 am->setConfiguration(config, locale8);
568
569 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
570}
571
572static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
573 jstring name,
574 jstring defType,
575 jstring defPackage)
576{
577 if (name == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700578 jniThrowException(env, "java/lang/NullPointerException", "name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 return 0;
580 }
581
582 AssetManager* am = assetManagerForJavaObject(env, clazz);
583 if (am == NULL) {
584 return 0;
585 }
586
587 const char16_t* name16 = env->GetStringChars(name, NULL);
588 jsize nameLen = env->GetStringLength(name);
589 const char16_t* defType16 = defType
590 ? env->GetStringChars(defType, NULL) : NULL;
591 jsize defTypeLen = defType
592 ? env->GetStringLength(defType) : 0;
593 const char16_t* defPackage16 = defPackage
594 ? env->GetStringChars(defPackage, NULL) : NULL;
595 jsize defPackageLen = defPackage
596 ? env->GetStringLength(defPackage) : 0;
597
598 jint ident = am->getResources().identifierForName(
599 name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
600
601 if (defPackage16) {
602 env->ReleaseStringChars(defPackage, defPackage16);
603 }
604 if (defType16) {
605 env->ReleaseStringChars(defType, defType16);
606 }
607 env->ReleaseStringChars(name, name16);
608
609 return ident;
610}
611
612static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
613 jint resid)
614{
615 AssetManager* am = assetManagerForJavaObject(env, clazz);
616 if (am == NULL) {
617 return NULL;
618 }
619
620 ResTable::resource_name name;
621 if (!am->getResources().getResourceName(resid, &name)) {
622 return NULL;
623 }
624
625 String16 str;
626 if (name.package != NULL) {
627 str.setTo(name.package, name.packageLen);
628 }
629 if (name.type != NULL) {
630 if (str.size() > 0) {
631 char16_t div = ':';
632 str.append(&div, 1);
633 }
634 str.append(name.type, name.typeLen);
635 }
636 if (name.name != NULL) {
637 if (str.size() > 0) {
638 char16_t div = '/';
639 str.append(&div, 1);
640 }
641 str.append(name.name, name.nameLen);
642 }
643
644 return env->NewString((const jchar*)str.string(), str.size());
645}
646
647static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
648 jint resid)
649{
650 AssetManager* am = assetManagerForJavaObject(env, clazz);
651 if (am == NULL) {
652 return NULL;
653 }
654
655 ResTable::resource_name name;
656 if (!am->getResources().getResourceName(resid, &name)) {
657 return NULL;
658 }
659
660 if (name.package != NULL) {
661 return env->NewString((const jchar*)name.package, name.packageLen);
662 }
663
664 return NULL;
665}
666
667static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
668 jint resid)
669{
670 AssetManager* am = assetManagerForJavaObject(env, clazz);
671 if (am == NULL) {
672 return NULL;
673 }
674
675 ResTable::resource_name name;
676 if (!am->getResources().getResourceName(resid, &name)) {
677 return NULL;
678 }
679
680 if (name.type != NULL) {
681 return env->NewString((const jchar*)name.type, name.typeLen);
682 }
683
684 return NULL;
685}
686
687static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
688 jint resid)
689{
690 AssetManager* am = assetManagerForJavaObject(env, clazz);
691 if (am == NULL) {
692 return NULL;
693 }
694
695 ResTable::resource_name name;
696 if (!am->getResources().getResourceName(resid, &name)) {
697 return NULL;
698 }
699
700 if (name.name != NULL) {
701 return env->NewString((const jchar*)name.name, name.nameLen);
702 }
703
704 return NULL;
705}
706
707static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
708 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700709 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 jobject outValue,
711 jboolean resolve)
712{
713 AssetManager* am = assetManagerForJavaObject(env, clazz);
714 if (am == NULL) {
715 return 0;
716 }
717 const ResTable& res(am->getResources());
718
719 Res_value value;
720 ResTable_config config;
721 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700722 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800723#if THROW_ON_BAD_ID
724 if (block == BAD_INDEX) {
725 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
726 return 0;
727 }
728#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 uint32_t ref = ident;
730 if (resolve) {
731 block = res.resolveReference(&value, block, &ref);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800732#if THROW_ON_BAD_ID
733 if (block == BAD_INDEX) {
734 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
735 return 0;
736 }
737#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
740}
741
742static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
743 jint ident, jint bagEntryId,
744 jobject outValue, jboolean resolve)
745{
746 AssetManager* am = assetManagerForJavaObject(env, clazz);
747 if (am == NULL) {
748 return 0;
749 }
750 const ResTable& res(am->getResources());
751
752 // Now lock down the resource object and start pulling stuff from it.
753 res.lock();
754
755 ssize_t block = -1;
756 Res_value value;
757
758 const ResTable::bag_entry* entry = NULL;
759 uint32_t typeSpecFlags;
760 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
761
762 for (ssize_t i=0; i<entryCount; i++) {
763 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
764 block = entry->stringBlock;
765 value = entry->map.value;
766 }
767 entry++;
768 }
769
770 res.unlock();
771
772 if (block < 0) {
773 return block;
774 }
775
776 uint32_t ref = ident;
777 if (resolve) {
778 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800779#if THROW_ON_BAD_ID
780 if (block == BAD_INDEX) {
781 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
782 return 0;
783 }
784#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
787}
788
789static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
790{
791 AssetManager* am = assetManagerForJavaObject(env, clazz);
792 if (am == NULL) {
793 return 0;
794 }
795 return am->getResources().getTableCount();
796}
797
798static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
799 jint block)
800{
801 AssetManager* am = assetManagerForJavaObject(env, clazz);
802 if (am == NULL) {
803 return 0;
804 }
805 return (jint)am->getResources().getTableStringBlock(block);
806}
807
808static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
809 jint cookie)
810{
811 AssetManager* am = assetManagerForJavaObject(env, clazz);
812 if (am == NULL) {
813 return NULL;
814 }
815 String8 name(am->getAssetPath((void*)cookie));
816 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700817 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 return NULL;
819 }
820 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 return str;
822}
823
824static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
825{
826 AssetManager* am = assetManagerForJavaObject(env, clazz);
827 if (am == NULL) {
828 return 0;
829 }
830 return (jint)(new ResTable::Theme(am->getResources()));
831}
832
833static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
834 jint themeInt)
835{
836 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
837 delete theme;
838}
839
840static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
841 jint themeInt,
842 jint styleRes,
843 jboolean force)
844{
845 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
846 theme->applyStyle(styleRes, force ? true : false);
847}
848
849static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
850 jint destInt, jint srcInt)
851{
852 ResTable::Theme* dest = (ResTable::Theme*)destInt;
853 ResTable::Theme* src = (ResTable::Theme*)srcInt;
854 dest->setTo(*src);
855}
856
857static jint android_content_AssetManager_loadThemeAttributeValue(
858 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
859{
860 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
861 const ResTable& res(theme->getResTable());
862
863 Res_value value;
864 // XXX value could be different in different configs!
865 uint32_t typeSpecFlags = 0;
866 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
867 uint32_t ref = 0;
868 if (resolve) {
869 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800870#if THROW_ON_BAD_ID
871 if (block == BAD_INDEX) {
872 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
873 return 0;
874 }
875#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
877 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
878}
879
880static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
881 jint themeInt, jint pri,
882 jstring tag, jstring prefix)
883{
884 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
885 const ResTable& res(theme->getResTable());
886
887 if (tag == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700888 jniThrowException(env, "java/lang/NullPointerException", "tag");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 return;
890 }
891
892 const char* tag8 = env->GetStringUTFChars(tag, NULL);
893 const char* prefix8 = NULL;
894 if (prefix != NULL) {
895 prefix8 = env->GetStringUTFChars(prefix, NULL);
896 }
897
898 // XXX Need to use params.
899 theme->dumpToLog();
900
901 if (prefix8 != NULL) {
902 env->ReleaseStringUTFChars(prefix, prefix8);
903 }
904 env->ReleaseStringUTFChars(tag, tag8);
905}
906
907static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
908 jint themeToken,
909 jint defStyleAttr,
910 jint defStyleRes,
911 jint xmlParserToken,
912 jintArray attrs,
913 jintArray outValues,
914 jintArray outIndices)
915{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700916 if (themeToken == 0) {
917 jniThrowException(env, "java/lang/NullPointerException", "theme token");
918 return JNI_FALSE;
919 }
920 if (attrs == NULL) {
921 jniThrowException(env, "java/lang/NullPointerException", "attrs");
922 return JNI_FALSE;
923 }
924 if (outValues == NULL) {
925 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 return JNI_FALSE;
927 }
928
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800929 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
930 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
933 const ResTable& res = theme->getResTable();
934 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700935 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 Res_value value;
937
938 const jsize NI = env->GetArrayLength(attrs);
939 const jsize NV = env->GetArrayLength(outValues);
940 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700941 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 return JNI_FALSE;
943 }
944
945 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
946 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700947 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 return JNI_FALSE;
949 }
950
951 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
952 jint* dest = baseDest;
953 if (dest == NULL) {
954 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700955 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 return JNI_FALSE;
957 }
958
959 jint* indices = NULL;
960 int indicesIdx = 0;
961 if (outIndices != NULL) {
962 if (env->GetArrayLength(outIndices) > NI) {
963 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
964 }
965 }
966
967 // Load default style from attribute, if specified...
968 uint32_t defStyleBagTypeSetFlags = 0;
969 if (defStyleAttr != 0) {
970 Res_value value;
971 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
972 if (value.dataType == Res_value::TYPE_REFERENCE) {
973 defStyleRes = value.data;
974 }
975 }
976 }
977
978 // Retrieve the style class associated with the current XML tag.
979 int style = 0;
980 uint32_t styleBagTypeSetFlags = 0;
981 if (xmlParser != NULL) {
982 ssize_t idx = xmlParser->indexOfStyle();
983 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
984 if (value.dataType == value.TYPE_ATTRIBUTE) {
985 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
986 value.dataType = Res_value::TYPE_NULL;
987 }
988 }
989 if (value.dataType == value.TYPE_REFERENCE) {
990 style = value.data;
991 }
992 }
993 }
994
995 // Now lock down the resource object and start pulling stuff from it.
996 res.lock();
997
998 // Retrieve the default style bag, if requested.
999 const ResTable::bag_entry* defStyleEnt = NULL;
1000 uint32_t defStyleTypeSetFlags = 0;
1001 ssize_t bagOff = defStyleRes != 0
1002 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
1003 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1004 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1005 (bagOff >= 0 ? bagOff : 0);
1006
1007 // Retrieve the style class bag, if requested.
1008 const ResTable::bag_entry* styleEnt = NULL;
1009 uint32_t styleTypeSetFlags = 0;
1010 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
1011 styleTypeSetFlags |= styleBagTypeSetFlags;
1012 const ResTable::bag_entry* endStyleEnt = styleEnt +
1013 (bagOff >= 0 ? bagOff : 0);
1014
1015 // Retrieve the XML attributes, if requested.
1016 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
1017 jsize ix=0;
1018 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
1019
1020 static const ssize_t kXmlBlock = 0x10000000;
1021
1022 // Now iterate through all of the attributes that the client has requested,
1023 // filling in each with whatever data we can find.
1024 ssize_t block = 0;
1025 uint32_t typeSetFlags;
1026 for (jsize ii=0; ii<NI; ii++) {
1027 const uint32_t curIdent = (uint32_t)src[ii];
1028
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001029 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 // Try to find a value for this attribute... we prioritize values
1032 // coming from, first XML attributes, then XML style, then default
1033 // style, and finally the theme.
1034 value.dataType = Res_value::TYPE_NULL;
1035 value.data = 0;
1036 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001037 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038
1039 // Skip through XML attributes until the end or the next possible match.
1040 while (ix < NX && curIdent > curXmlAttr) {
1041 ix++;
1042 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1043 }
1044 // Retrieve the current XML attribute if it matches, and step to next.
1045 if (ix < NX && curIdent == curXmlAttr) {
1046 block = kXmlBlock;
1047 xmlParser->getAttributeValue(ix, &value);
1048 ix++;
1049 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001050 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1051 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053
1054 // Skip through the style values until the end or the next possible match.
1055 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1056 styleEnt++;
1057 }
1058 // Retrieve the current style attribute if it matches, and step to next.
1059 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1060 if (value.dataType == Res_value::TYPE_NULL) {
1061 block = styleEnt->stringBlock;
1062 typeSetFlags = styleTypeSetFlags;
1063 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001064 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1065 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 }
1067 styleEnt++;
1068 }
1069
1070 // Skip through the default style values until the end or the next possible match.
1071 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1072 defStyleEnt++;
1073 }
1074 // Retrieve the current default style attribute if it matches, and step to next.
1075 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1076 if (value.dataType == Res_value::TYPE_NULL) {
1077 block = defStyleEnt->stringBlock;
1078 typeSetFlags = defStyleTypeSetFlags;
1079 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001080 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1081 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083 defStyleEnt++;
1084 }
1085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 uint32_t resid = 0;
1087 if (value.dataType != Res_value::TYPE_NULL) {
1088 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001089 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1090 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001092 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1093 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 } else {
1095 // If we still don't have a value for this attribute, try to find
1096 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1098 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001099 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1100 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001101 newBlock = res.resolveReference(&value, block, &resid,
1102 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001103#if THROW_ON_BAD_ID
1104 if (newBlock == BAD_INDEX) {
1105 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1106 return JNI_FALSE;
1107 }
1108#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001110 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1111 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113 }
1114
1115 // Deal with the special @null value -- it turns back to TYPE_NULL.
1116 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001117 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001119 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001122 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1123 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124
1125 // Write the final value back to Java.
1126 dest[STYLE_TYPE] = value.dataType;
1127 dest[STYLE_DATA] = value.data;
1128 dest[STYLE_ASSET_COOKIE] =
1129 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1130 dest[STYLE_RESOURCE_ID] = resid;
1131 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001132 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133
1134 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1135 indicesIdx++;
1136 indices[indicesIdx] = ii;
1137 }
1138
1139 dest += STYLE_NUM_ENTRIES;
1140 }
1141
1142 res.unlock();
1143
1144 if (indices != NULL) {
1145 indices[0] = indicesIdx;
1146 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1147 }
1148 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1149 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1150
1151 return JNI_TRUE;
1152}
1153
1154static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1155 jint xmlParserToken,
1156 jintArray attrs,
1157 jintArray outValues,
1158 jintArray outIndices)
1159{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001160 if (xmlParserToken == 0) {
1161 jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
1162 return JNI_FALSE;
1163 }
1164 if (attrs == NULL) {
1165 jniThrowException(env, "java/lang/NullPointerException", "attrs");
1166 return JNI_FALSE;
1167 }
1168 if (outValues == NULL) {
1169 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 return JNI_FALSE;
1171 }
1172
1173 AssetManager* am = assetManagerForJavaObject(env, clazz);
1174 if (am == NULL) {
1175 return JNI_FALSE;
1176 }
1177 const ResTable& res(am->getResources());
1178 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001179 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 Res_value value;
1181
1182 const jsize NI = env->GetArrayLength(attrs);
1183 const jsize NV = env->GetArrayLength(outValues);
1184 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001185 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 return JNI_FALSE;
1187 }
1188
1189 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1190 if (src == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001191 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 return JNI_FALSE;
1193 }
1194
1195 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1196 jint* dest = baseDest;
1197 if (dest == NULL) {
1198 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001199 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 return JNI_FALSE;
1201 }
1202
1203 jint* indices = NULL;
1204 int indicesIdx = 0;
1205 if (outIndices != NULL) {
1206 if (env->GetArrayLength(outIndices) > NI) {
1207 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1208 }
1209 }
1210
1211 // Now lock down the resource object and start pulling stuff from it.
1212 res.lock();
1213
1214 // Retrieve the XML attributes, if requested.
1215 const jsize NX = xmlParser->getAttributeCount();
1216 jsize ix=0;
1217 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1218
1219 static const ssize_t kXmlBlock = 0x10000000;
1220
1221 // Now iterate through all of the attributes that the client has requested,
1222 // filling in each with whatever data we can find.
1223 ssize_t block = 0;
1224 uint32_t typeSetFlags;
1225 for (jsize ii=0; ii<NI; ii++) {
1226 const uint32_t curIdent = (uint32_t)src[ii];
1227
1228 // Try to find a value for this attribute...
1229 value.dataType = Res_value::TYPE_NULL;
1230 value.data = 0;
1231 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001232 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233
1234 // Skip through XML attributes until the end or the next possible match.
1235 while (ix < NX && curIdent > curXmlAttr) {
1236 ix++;
1237 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1238 }
1239 // Retrieve the current XML attribute if it matches, and step to next.
1240 if (ix < NX && curIdent == curXmlAttr) {
1241 block = kXmlBlock;
1242 xmlParser->getAttributeValue(ix, &value);
1243 ix++;
1244 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1245 }
1246
1247 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1248 uint32_t resid = 0;
1249 if (value.dataType != Res_value::TYPE_NULL) {
1250 // Take care of resolving the found resource to its final value.
1251 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001252 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1253 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001254#if THROW_ON_BAD_ID
1255 if (newBlock == BAD_INDEX) {
1256 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1257 return JNI_FALSE;
1258 }
1259#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 if (newBlock >= 0) block = newBlock;
1261 }
1262
1263 // Deal with the special @null value -- it turns back to TYPE_NULL.
1264 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1265 value.dataType = Res_value::TYPE_NULL;
1266 }
1267
1268 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1269
1270 // Write the final value back to Java.
1271 dest[STYLE_TYPE] = value.dataType;
1272 dest[STYLE_DATA] = value.data;
1273 dest[STYLE_ASSET_COOKIE] =
1274 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1275 dest[STYLE_RESOURCE_ID] = resid;
1276 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001277 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278
1279 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1280 indicesIdx++;
1281 indices[indicesIdx] = ii;
1282 }
1283
1284 dest += STYLE_NUM_ENTRIES;
1285 }
1286
1287 res.unlock();
1288
1289 if (indices != NULL) {
1290 indices[0] = indicesIdx;
1291 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1292 }
1293
1294 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1295 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1296
1297 return JNI_TRUE;
1298}
1299
1300static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1301 jint id)
1302{
1303 AssetManager* am = assetManagerForJavaObject(env, clazz);
1304 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001305 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 }
1307 const ResTable& res(am->getResources());
1308
1309 res.lock();
1310 const ResTable::bag_entry* defStyleEnt = NULL;
1311 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1312 res.unlock();
1313
1314 return bagOff;
1315}
1316
1317static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1318 jint id,
1319 jintArray outValues)
1320{
1321 if (outValues == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001322 jniThrowException(env, "java/lang/NullPointerException", "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 return JNI_FALSE;
1324 }
1325
1326 AssetManager* am = assetManagerForJavaObject(env, clazz);
1327 if (am == NULL) {
1328 return JNI_FALSE;
1329 }
1330 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001331 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 Res_value value;
1333 ssize_t block;
1334
1335 const jsize NV = env->GetArrayLength(outValues);
1336
1337 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1338 jint* dest = baseDest;
1339 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001340 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 return JNI_FALSE;
1342 }
1343
1344 // Now lock down the resource object and start pulling stuff from it.
1345 res.lock();
1346
1347 const ResTable::bag_entry* arrayEnt = NULL;
1348 uint32_t arrayTypeSetFlags = 0;
1349 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1350 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1351 (bagOff >= 0 ? bagOff : 0);
1352
1353 int i = 0;
1354 uint32_t typeSetFlags;
1355 while (i < NV && arrayEnt < endArrayEnt) {
1356 block = arrayEnt->stringBlock;
1357 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001358 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 value = arrayEnt->map.value;
1360
1361 uint32_t resid = 0;
1362 if (value.dataType != Res_value::TYPE_NULL) {
1363 // Take care of resolving the found resource to its final value.
1364 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001365 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1366 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001367#if THROW_ON_BAD_ID
1368 if (newBlock == BAD_INDEX) {
1369 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1370 return JNI_FALSE;
1371 }
1372#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 if (newBlock >= 0) block = newBlock;
1374 }
1375
1376 // Deal with the special @null value -- it turns back to TYPE_NULL.
1377 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1378 value.dataType = Res_value::TYPE_NULL;
1379 }
1380
1381 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1382
1383 // Write the final value back to Java.
1384 dest[STYLE_TYPE] = value.dataType;
1385 dest[STYLE_DATA] = value.data;
1386 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1387 dest[STYLE_RESOURCE_ID] = resid;
1388 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001389 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 dest += STYLE_NUM_ENTRIES;
1391 i+= STYLE_NUM_ENTRIES;
1392 arrayEnt++;
1393 }
1394
1395 i /= STYLE_NUM_ENTRIES;
1396
1397 res.unlock();
1398
1399 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1400
1401 return i;
1402}
1403
1404static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1405 jint cookie,
1406 jstring fileName)
1407{
1408 AssetManager* am = assetManagerForJavaObject(env, clazz);
1409 if (am == NULL) {
1410 return 0;
1411 }
1412
1413 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1414
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001415 if (fileName == NULL) {
1416 jniThrowException(env, "java/lang/NullPointerException", "fileName");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 return 0;
1418 }
1419
1420 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1421 Asset* a = cookie
1422 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1423 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1424
1425 if (a == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001426 jniThrowException(env, "java/io/FileNotFoundException", fileName8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 env->ReleaseStringUTFChars(fileName, fileName8);
1428 return 0;
1429 }
1430 env->ReleaseStringUTFChars(fileName, fileName8);
1431
1432 ResXMLTree* block = new ResXMLTree();
1433 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1434 a->close();
1435 delete a;
1436
1437 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001438 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 return 0;
1440 }
1441
1442 return (jint)block;
1443}
1444
1445static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1446 jint arrayResId)
1447{
1448 AssetManager* am = assetManagerForJavaObject(env, clazz);
1449 if (am == NULL) {
1450 return NULL;
1451 }
1452 const ResTable& res(am->getResources());
1453
1454 const ResTable::bag_entry* startOfBag;
1455 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1456 if (N < 0) {
1457 return NULL;
1458 }
1459
1460 jintArray array = env->NewIntArray(N * 2);
1461 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001462 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 res.unlockBag(startOfBag);
1464 return NULL;
1465 }
1466
1467 Res_value value;
1468 const ResTable::bag_entry* bag = startOfBag;
1469 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1470 jint stringIndex = -1;
1471 jint stringBlock = 0;
1472 value = bag->map.value;
1473
1474 // Take care of resolving the found resource to its final value.
1475 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1476 if (value.dataType == Res_value::TYPE_STRING) {
1477 stringIndex = value.data;
1478 }
1479
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001480#if THROW_ON_BAD_ID
1481 if (stringBlock == BAD_INDEX) {
1482 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1483 return array;
1484 }
1485#endif
1486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 //todo: It might be faster to allocate a C array to contain
1488 // the blocknums and indices, put them in there and then
1489 // do just one SetIntArrayRegion()
1490 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1491 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1492 j = j + 2;
1493 }
1494 res.unlockBag(startOfBag);
1495 return array;
1496}
1497
1498static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1499 jint arrayResId)
1500{
1501 AssetManager* am = assetManagerForJavaObject(env, clazz);
1502 if (am == NULL) {
1503 return NULL;
1504 }
1505 const ResTable& res(am->getResources());
1506
1507 jclass cls = env->FindClass("java/lang/String");
1508 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1509 if (cls == NULL) {
1510 return NULL;
1511 }
1512
1513 const ResTable::bag_entry* startOfBag;
1514 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1515 if (N < 0) {
1516 return NULL;
1517 }
1518
1519 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001520 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 res.unlockBag(startOfBag);
1522 return NULL;
1523 }
1524
1525 Res_value value;
1526 const ResTable::bag_entry* bag = startOfBag;
1527 size_t strLen = 0;
1528 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1529 value = bag->map.value;
1530 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 // Take care of resolving the found resource to its final value.
1533 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001534#if THROW_ON_BAD_ID
1535 if (block == BAD_INDEX) {
1536 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1537 return array;
1538 }
1539#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001541 const ResStringPool* pool = res.getTableStringBlock(block);
1542 const char* str8 = pool->string8At(value.data, &strLen);
1543 if (str8 != NULL) {
1544 str = env->NewStringUTF(str8);
1545 } else {
1546 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1547 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001548 }
1549
1550 // If one of our NewString{UTF} calls failed due to memory, an
1551 // exception will be pending.
1552 if (env->ExceptionCheck()) {
1553 res.unlockBag(startOfBag);
1554 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
Kenny Root780d2a12010-02-22 22:36:26 -08001556
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001557 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001558
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001559 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1560 // If we have a large amount of strings in our array, we might
1561 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001562 env->DeleteLocalRef(str);
1563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
1565 res.unlockBag(startOfBag);
1566 return array;
1567}
1568
1569static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1570 jint arrayResId)
1571{
1572 AssetManager* am = assetManagerForJavaObject(env, clazz);
1573 if (am == NULL) {
1574 return NULL;
1575 }
1576 const ResTable& res(am->getResources());
1577
1578 const ResTable::bag_entry* startOfBag;
1579 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1580 if (N < 0) {
1581 return NULL;
1582 }
1583
1584 jintArray array = env->NewIntArray(N);
1585 if (array == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001586 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 res.unlockBag(startOfBag);
1588 return NULL;
1589 }
1590
1591 Res_value value;
1592 const ResTable::bag_entry* bag = startOfBag;
1593 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1594 value = bag->map.value;
1595
1596 // Take care of resolving the found resource to its final value.
1597 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001598#if THROW_ON_BAD_ID
1599 if (block == BAD_INDEX) {
1600 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1601 return array;
1602 }
1603#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 if (value.dataType >= Res_value::TYPE_FIRST_INT
1605 && value.dataType <= Res_value::TYPE_LAST_INT) {
1606 int intVal = value.data;
1607 env->SetIntArrayRegion(array, i, 1, &intVal);
1608 }
1609 }
1610 res.unlockBag(startOfBag);
1611 return array;
1612}
1613
1614static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1615{
1616 AssetManager* am = new AssetManager();
1617 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001618 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 return;
1620 }
1621
1622 am->addDefaultAssets();
1623
1624 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1625 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1626}
1627
1628static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1629{
1630 AssetManager* am = (AssetManager*)
1631 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1632 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1633 if (am != NULL) {
1634 delete am;
1635 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1636 }
1637}
1638
1639static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1640{
1641 return Asset::getGlobalCount();
1642}
1643
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001644static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1645{
1646 String8 alloc = Asset::getAssetAllocations();
1647 if (alloc.length() <= 0) {
1648 return NULL;
1649 }
1650
1651 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001652 return str;
1653}
1654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1656{
1657 return AssetManager::getGlobalCount();
1658}
1659
1660// ----------------------------------------------------------------------------
1661
1662/*
1663 * JNI registration.
1664 */
1665static JNINativeMethod gAssetManagerMethods[] = {
1666 /* name, signature, funcPtr */
1667
1668 // Basic asset stuff.
1669 { "openAsset", "(Ljava/lang/String;I)I",
1670 (void*) android_content_AssetManager_openAsset },
1671 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1672 (void*) android_content_AssetManager_openAssetFd },
1673 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1674 (void*) android_content_AssetManager_openNonAssetNative },
1675 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1676 (void*) android_content_AssetManager_openNonAssetFdNative },
1677 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1678 (void*) android_content_AssetManager_list },
1679 { "destroyAsset", "(I)V",
1680 (void*) android_content_AssetManager_destroyAsset },
1681 { "readAssetChar", "(I)I",
1682 (void*) android_content_AssetManager_readAssetChar },
1683 { "readAsset", "(I[BII)I",
1684 (void*) android_content_AssetManager_readAsset },
1685 { "seekAsset", "(IJI)J",
1686 (void*) android_content_AssetManager_seekAsset },
1687 { "getAssetLength", "(I)J",
1688 (void*) android_content_AssetManager_getAssetLength },
1689 { "getAssetRemainingLength", "(I)J",
1690 (void*) android_content_AssetManager_getAssetRemainingLength },
1691 { "addAssetPath", "(Ljava/lang/String;)I",
1692 (void*) android_content_AssetManager_addAssetPath },
1693 { "isUpToDate", "()Z",
1694 (void*) android_content_AssetManager_isUpToDate },
1695
1696 // Resources.
1697 { "setLocale", "(Ljava/lang/String;)V",
1698 (void*) android_content_AssetManager_setLocale },
1699 { "getLocales", "()[Ljava/lang/String;",
1700 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001701 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 (void*) android_content_AssetManager_setConfiguration },
1703 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1704 (void*) android_content_AssetManager_getResourceIdentifier },
1705 { "getResourceName","(I)Ljava/lang/String;",
1706 (void*) android_content_AssetManager_getResourceName },
1707 { "getResourcePackageName","(I)Ljava/lang/String;",
1708 (void*) android_content_AssetManager_getResourcePackageName },
1709 { "getResourceTypeName","(I)Ljava/lang/String;",
1710 (void*) android_content_AssetManager_getResourceTypeName },
1711 { "getResourceEntryName","(I)Ljava/lang/String;",
1712 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001713 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 (void*) android_content_AssetManager_loadResourceValue },
1715 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1716 (void*) android_content_AssetManager_loadResourceBagValue },
1717 { "getStringBlockCount","()I",
1718 (void*) android_content_AssetManager_getStringBlockCount },
1719 { "getNativeStringBlock","(I)I",
1720 (void*) android_content_AssetManager_getNativeStringBlock },
1721 { "getCookieName","(I)Ljava/lang/String;",
1722 (void*) android_content_AssetManager_getCookieName },
1723
1724 // Themes.
1725 { "newTheme", "()I",
1726 (void*) android_content_AssetManager_newTheme },
1727 { "deleteTheme", "(I)V",
1728 (void*) android_content_AssetManager_deleteTheme },
1729 { "applyThemeStyle", "(IIZ)V",
1730 (void*) android_content_AssetManager_applyThemeStyle },
1731 { "copyTheme", "(II)V",
1732 (void*) android_content_AssetManager_copyTheme },
1733 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1734 (void*) android_content_AssetManager_loadThemeAttributeValue },
1735 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1736 (void*) android_content_AssetManager_dumpTheme },
1737 { "applyStyle","(IIII[I[I[I)Z",
1738 (void*) android_content_AssetManager_applyStyle },
1739 { "retrieveAttributes","(I[I[I[I)Z",
1740 (void*) android_content_AssetManager_retrieveAttributes },
1741 { "getArraySize","(I)I",
1742 (void*) android_content_AssetManager_getArraySize },
1743 { "retrieveArray","(I[I)I",
1744 (void*) android_content_AssetManager_retrieveArray },
1745
1746 // XML files.
1747 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1748 (void*) android_content_AssetManager_openXmlAssetNative },
1749
1750 // Arrays.
1751 { "getArrayStringResource","(I)[Ljava/lang/String;",
1752 (void*) android_content_AssetManager_getArrayStringResource },
1753 { "getArrayStringInfo","(I)[I",
1754 (void*) android_content_AssetManager_getArrayStringInfo },
1755 { "getArrayIntResource","(I)[I",
1756 (void*) android_content_AssetManager_getArrayIntResource },
1757
1758 // Bookkeeping.
1759 { "init", "()V",
1760 (void*) android_content_AssetManager_init },
1761 { "destroy", "()V",
1762 (void*) android_content_AssetManager_destroy },
1763 { "getGlobalAssetCount", "()I",
1764 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001765 { "getAssetAllocations", "()Ljava/lang/String;",
1766 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 { "getGlobalAssetManagerCount", "()I",
1768 (void*) android_content_AssetManager_getGlobalAssetCount },
1769};
1770
1771int register_android_content_AssetManager(JNIEnv* env)
1772{
1773 jclass typedValue = env->FindClass("android/util/TypedValue");
1774 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1775 gTypedValueOffsets.mType
1776 = env->GetFieldID(typedValue, "type", "I");
1777 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1778 gTypedValueOffsets.mData
1779 = env->GetFieldID(typedValue, "data", "I");
1780 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1781 gTypedValueOffsets.mString
1782 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1783 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1784 gTypedValueOffsets.mAssetCookie
1785 = env->GetFieldID(typedValue, "assetCookie", "I");
1786 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1787 gTypedValueOffsets.mResourceId
1788 = env->GetFieldID(typedValue, "resourceId", "I");
1789 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1790 gTypedValueOffsets.mChangingConfigurations
1791 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1792 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1793 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1794 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1795
1796 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1797 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1798 gAssetFileDescriptorOffsets.mFd
1799 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1800 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1801 gAssetFileDescriptorOffsets.mStartOffset
1802 = env->GetFieldID(assetFd, "mStartOffset", "J");
1803 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1804 gAssetFileDescriptorOffsets.mLength
1805 = env->GetFieldID(assetFd, "mLength", "J");
1806 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1807
1808 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1809 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1810 gAssetManagerOffsets.mObject
1811 = env->GetFieldID(assetManager, "mObject", "I");
1812 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1813
1814 g_stringClass = env->FindClass("java/lang/String");
1815
1816 return AndroidRuntime::registerNativeMethods(env,
1817 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1818}
1819
1820}; // namespace android