blob: b0e92e4a3c1870efce7ceff146138e1fc73e50ff [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**
Elliott Hughes69a017b2011-04-08 14:10:28 -07005** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughes69a017b2011-04-08 14:10:28 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughes69a017b2011-04-08 14:10:28 -070011** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** 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"
Elliott Hughes69a017b2011-04-08 14:10:28 -070027#include "ScopedStringChars.h"
28#include "ScopedUtfChars.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029#include "android_util_Binder.h"
30#include <utils/misc.h>
31#include <android_runtime/AndroidRuntime.h>
32#include <utils/Log.h>
33
34#include <utils/Asset.h>
35#include <utils/AssetManager.h>
36#include <utils/ResourceTypes.h>
37
38#include <stdio.h>
39
40namespace android {
41
42// ----------------------------------------------------------------------------
43
44static struct typedvalue_offsets_t
45{
46 jfieldID mType;
47 jfieldID mData;
48 jfieldID mString;
49 jfieldID mAssetCookie;
50 jfieldID mResourceId;
51 jfieldID mChangingConfigurations;
52 jfieldID mDensity;
53} gTypedValueOffsets;
54
55static struct assetfiledescriptor_offsets_t
56{
57 jfieldID mFd;
58 jfieldID mStartOffset;
59 jfieldID mLength;
60} gAssetFileDescriptorOffsets;
61
62static struct assetmanager_offsets_t
63{
64 jfieldID mObject;
65} gAssetManagerOffsets;
66
67jclass g_stringClass = NULL;
68
69// ----------------------------------------------------------------------------
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -070072 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 STYLE_TYPE = 0,
74 STYLE_DATA = 1,
75 STYLE_ASSET_COOKIE = 2,
76 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -070077 STYLE_CHANGING_CONFIGURATIONS = 4,
78 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079};
80
81static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
82 const Res_value& value, uint32_t ref, ssize_t block,
83 uint32_t typeSpecFlags, ResTable_config* config = NULL);
84
85jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
86 const Res_value& value, uint32_t ref, ssize_t block,
87 uint32_t typeSpecFlags, ResTable_config* config)
88{
89 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
90 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
91 (jint)table->getTableCookie(block));
92 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
93 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
94 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
95 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
96 typeSpecFlags);
97 if (config != NULL) {
98 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
99 }
100 return block;
101}
102
103// ----------------------------------------------------------------------------
104
105// this guy is exported to other jni routines
106AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
107{
108 AssetManager* am = (AssetManager*)env->GetIntField(obj, gAssetManagerOffsets.mObject);
109 if (am != NULL) {
110 return am;
111 }
112 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
113 return NULL;
114}
115
116static jint android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
117 jstring fileName, jint mode)
118{
119 AssetManager* am = assetManagerForJavaObject(env, clazz);
120 if (am == NULL) {
121 return 0;
122 }
123
124 LOGV("openAsset in %p (Java object %p)\n", am, clazz);
125
Elliott Hughes69a017b2011-04-08 14:10:28 -0700126 ScopedUtfChars fileName8(env, fileName);
127 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 return -1;
129 }
130
131 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
132 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700133 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 return -1;
135 }
136
Elliott Hughes69a017b2011-04-08 14:10:28 -0700137 Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
139 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700140 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 return -1;
142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
144 //printf("Created Asset Stream: %p\n", a);
145
146 return (jint)a;
147}
148
149static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
150{
Kenny Rootddb76c42010-11-24 12:56:06 -0800151 off64_t startOffset, length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 int fd = a->openFileDescriptor(&startOffset, &length);
153 delete a;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 if (fd < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700156 jniThrowException(env, "java/io/FileNotFoundException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 "This file can not be opened as a file descriptor; it is probably compressed");
158 return NULL;
159 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
162 if (offsets == NULL) {
163 close(fd);
164 return NULL;
165 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 offsets[0] = startOffset;
168 offsets[1] = length;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700171
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700172 jobject fileDesc = jniCreateFileDescriptor(env, fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 if (fileDesc == NULL) {
174 close(fd);
175 return NULL;
176 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 return newParcelFileDescriptor(env, fileDesc);
179}
180
181static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
182 jstring fileName, jlongArray outOffsets)
183{
184 AssetManager* am = assetManagerForJavaObject(env, clazz);
185 if (am == NULL) {
186 return NULL;
187 }
188
189 LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
190
Elliott Hughes69a017b2011-04-08 14:10:28 -0700191 ScopedUtfChars fileName8(env, fileName);
192 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 return NULL;
194 }
195
Elliott Hughes69a017b2011-04-08 14:10:28 -0700196 Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
198 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700199 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 return NULL;
201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
203 //printf("Created Asset Stream: %p\n", a);
204
205 return returnParcelFileDescriptor(env, a, outOffsets);
206}
207
208static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
209 jint cookie,
210 jstring fileName,
211 jint mode)
212{
213 AssetManager* am = assetManagerForJavaObject(env, clazz);
214 if (am == NULL) {
215 return 0;
216 }
217
218 LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
219
Elliott Hughes69a017b2011-04-08 14:10:28 -0700220 ScopedUtfChars fileName8(env, fileName);
221 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 return -1;
223 }
224
225 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
226 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700227 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 return -1;
229 }
230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -0700232 ? am->openNonAsset((void*)cookie, fileName8.c_str(), (Asset::AccessMode)mode)
233 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234
235 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700236 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 return -1;
238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 //printf("Created Asset Stream: %p\n", a);
241
242 return (jint)a;
243}
244
245static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
246 jint cookie,
247 jstring fileName,
248 jlongArray outOffsets)
249{
250 AssetManager* am = assetManagerForJavaObject(env, clazz);
251 if (am == NULL) {
252 return NULL;
253 }
254
255 LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
256
Elliott Hughes69a017b2011-04-08 14:10:28 -0700257 ScopedUtfChars fileName8(env, fileName);
258 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 return NULL;
260 }
261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -0700263 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_RANDOM)
264 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
266 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700267 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 return NULL;
269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270
271 //printf("Created Asset Stream: %p\n", a);
272
273 return returnParcelFileDescriptor(env, a, outOffsets);
274}
275
276static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
277 jstring fileName)
278{
279 AssetManager* am = assetManagerForJavaObject(env, clazz);
280 if (am == NULL) {
281 return NULL;
282 }
283
Elliott Hughes69a017b2011-04-08 14:10:28 -0700284 ScopedUtfChars fileName8(env, fileName);
285 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 return NULL;
287 }
288
Elliott Hughes69a017b2011-04-08 14:10:28 -0700289 AssetDir* dir = am->openDir(fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290
291 if (dir == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700292 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 return NULL;
294 }
295
296 jclass cls = env->FindClass("java/lang/String");
297 LOG_FATAL_IF(cls == NULL, "No string class?!?");
298 if (cls == NULL) {
299 delete dir;
300 return NULL;
301 }
302
303 size_t N = dir->getFileCount();
304
305 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
306 cls, NULL);
307 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 delete dir;
309 return NULL;
310 }
311
312 for (size_t i=0; i<N; i++) {
313 const String8& name = dir->getFileName(i);
314 jstring str = env->NewStringUTF(name.string());
315 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 delete dir;
317 return NULL;
318 }
319 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700320 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
322
323 delete dir;
324
325 return array;
326}
327
328static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
329 jint asset)
330{
331 Asset* a = (Asset*)asset;
332
333 //printf("Destroying Asset Stream: %p\n", a);
334
335 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700336 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 return;
338 }
339
340 delete a;
341}
342
343static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
344 jint asset)
345{
346 Asset* a = (Asset*)asset;
347
348 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700349 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 return -1;
351 }
352
353 uint8_t b;
354 ssize_t res = a->read(&b, 1);
355 return res == 1 ? b : -1;
356}
357
358static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
359 jint asset, jbyteArray bArray,
360 jint off, jint len)
361{
362 Asset* a = (Asset*)asset;
363
364 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700365 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 return -1;
367 }
368
369 if (len == 0) {
370 return 0;
371 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 jsize bLen = env->GetArrayLength(bArray);
374 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700375 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 return -1;
377 }
378
379 jbyte* b = env->GetByteArrayElements(bArray, NULL);
380 ssize_t res = a->read(b+off, len);
381 env->ReleaseByteArrayElements(bArray, b, 0);
382
383 if (res > 0) return res;
384
385 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700386 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
388 return -1;
389}
390
391static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
392 jint asset,
393 jlong offset, jint whence)
394{
395 Asset* a = (Asset*)asset;
396
397 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700398 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return -1;
400 }
401
402 return a->seek(
403 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
404}
405
406static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
407 jint asset)
408{
409 Asset* a = (Asset*)asset;
410
411 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700412 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 return -1;
414 }
415
416 return a->getLength();
417}
418
419static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
420 jint asset)
421{
422 Asset* a = (Asset*)asset;
423
424 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700425 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 return -1;
427 }
428
429 return a->getRemainingLength();
430}
431
432static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
433 jstring path)
434{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700435 ScopedUtfChars path8(env, path);
436 if (path8.c_str() == NULL) {
437 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
439
440 AssetManager* am = assetManagerForJavaObject(env, clazz);
441 if (am == NULL) {
442 return JNI_FALSE;
443 }
444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 void* cookie;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700446 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447
448 return (res) ? (jint)cookie : 0;
449}
450
451static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
452{
453 AssetManager* am = assetManagerForJavaObject(env, clazz);
454 if (am == NULL) {
455 return JNI_TRUE;
456 }
457 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
458}
459
460static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
461 jstring locale)
462{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700463 ScopedUtfChars locale8(env, locale);
464 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 return;
466 }
467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 AssetManager* am = assetManagerForJavaObject(env, clazz);
469 if (am == NULL) {
470 return;
471 }
472
Elliott Hughes69a017b2011-04-08 14:10:28 -0700473 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474}
475
476static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
477{
478 Vector<String8> locales;
479
480 AssetManager* am = assetManagerForJavaObject(env, clazz);
481 if (am == NULL) {
482 return NULL;
483 }
484
485 am->getLocales(&locales);
486
487 const int N = locales.size();
488
489 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
490 if (result == NULL) {
491 return NULL;
492 }
493
494 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700495 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700496 if (str == NULL) {
497 return NULL;
498 }
499 env->SetObjectArrayElement(result, i, str);
500 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 }
502
503 return result;
504}
505
506static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
507 jint mcc, jint mnc,
508 jstring locale, jint orientation,
509 jint touchscreen, jint density,
510 jint keyboard, jint keyboardHidden,
511 jint navigation,
512 jint screenWidth, jint screenHeight,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700513 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100514 jint screenLayout, jint uiMode,
515 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516{
517 AssetManager* am = assetManagerForJavaObject(env, clazz);
518 if (am == NULL) {
519 return;
520 }
521
522 ResTable_config config;
523 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 config.mcc = (uint16_t)mcc;
528 config.mnc = (uint16_t)mnc;
529 config.orientation = (uint8_t)orientation;
530 config.touchscreen = (uint8_t)touchscreen;
531 config.density = (uint16_t)density;
532 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700533 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 config.navigation = (uint8_t)navigation;
535 config.screenWidth = (uint16_t)screenWidth;
536 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700537 config.screenWidthDp = (uint16_t)screenWidthDp;
538 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700539 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100540 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 config.sdkVersion = (uint16_t)sdkVersion;
542 config.minorVersion = 0;
543 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
546}
547
548static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
549 jstring name,
550 jstring defType,
551 jstring defPackage)
552{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700553 ScopedStringChars name16(env, name);
554 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 return 0;
556 }
557
558 AssetManager* am = assetManagerForJavaObject(env, clazz);
559 if (am == NULL) {
560 return 0;
561 }
562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 const char16_t* defType16 = defType
564 ? env->GetStringChars(defType, NULL) : NULL;
565 jsize defTypeLen = defType
566 ? env->GetStringLength(defType) : 0;
567 const char16_t* defPackage16 = defPackage
568 ? env->GetStringChars(defPackage, NULL) : NULL;
569 jsize defPackageLen = defPackage
570 ? env->GetStringLength(defPackage) : 0;
571
572 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700573 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574
575 if (defPackage16) {
576 env->ReleaseStringChars(defPackage, defPackage16);
577 }
578 if (defType16) {
579 env->ReleaseStringChars(defType, defType16);
580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581
582 return ident;
583}
584
585static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
586 jint resid)
587{
588 AssetManager* am = assetManagerForJavaObject(env, clazz);
589 if (am == NULL) {
590 return NULL;
591 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 ResTable::resource_name name;
594 if (!am->getResources().getResourceName(resid, &name)) {
595 return NULL;
596 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 String16 str;
599 if (name.package != NULL) {
600 str.setTo(name.package, name.packageLen);
601 }
602 if (name.type != NULL) {
603 if (str.size() > 0) {
604 char16_t div = ':';
605 str.append(&div, 1);
606 }
607 str.append(name.type, name.typeLen);
608 }
609 if (name.name != NULL) {
610 if (str.size() > 0) {
611 char16_t div = '/';
612 str.append(&div, 1);
613 }
614 str.append(name.name, name.nameLen);
615 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 return env->NewString((const jchar*)str.string(), str.size());
618}
619
620static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
621 jint resid)
622{
623 AssetManager* am = assetManagerForJavaObject(env, clazz);
624 if (am == NULL) {
625 return NULL;
626 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 ResTable::resource_name name;
629 if (!am->getResources().getResourceName(resid, &name)) {
630 return NULL;
631 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 if (name.package != NULL) {
634 return env->NewString((const jchar*)name.package, name.packageLen);
635 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 return NULL;
638}
639
640static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
641 jint resid)
642{
643 AssetManager* am = assetManagerForJavaObject(env, clazz);
644 if (am == NULL) {
645 return NULL;
646 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 ResTable::resource_name name;
649 if (!am->getResources().getResourceName(resid, &name)) {
650 return NULL;
651 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 if (name.type != NULL) {
654 return env->NewString((const jchar*)name.type, name.typeLen);
655 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 return NULL;
658}
659
660static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
661 jint resid)
662{
663 AssetManager* am = assetManagerForJavaObject(env, clazz);
664 if (am == NULL) {
665 return NULL;
666 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 ResTable::resource_name name;
669 if (!am->getResources().getResourceName(resid, &name)) {
670 return NULL;
671 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 if (name.name != NULL) {
674 return env->NewString((const jchar*)name.name, name.nameLen);
675 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 return NULL;
678}
679
680static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
681 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700682 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 jobject outValue,
684 jboolean resolve)
685{
686 AssetManager* am = assetManagerForJavaObject(env, clazz);
687 if (am == NULL) {
688 return 0;
689 }
690 const ResTable& res(am->getResources());
691
692 Res_value value;
693 ResTable_config config;
694 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700695 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800696#if THROW_ON_BAD_ID
697 if (block == BAD_INDEX) {
698 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
699 return 0;
700 }
701#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 uint32_t ref = ident;
703 if (resolve) {
704 block = res.resolveReference(&value, block, &ref);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800705#if THROW_ON_BAD_ID
706 if (block == BAD_INDEX) {
707 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
708 return 0;
709 }
710#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 }
712 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
713}
714
715static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
716 jint ident, jint bagEntryId,
717 jobject outValue, jboolean resolve)
718{
719 AssetManager* am = assetManagerForJavaObject(env, clazz);
720 if (am == NULL) {
721 return 0;
722 }
723 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 // Now lock down the resource object and start pulling stuff from it.
726 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 ssize_t block = -1;
729 Res_value value;
730
731 const ResTable::bag_entry* entry = NULL;
732 uint32_t typeSpecFlags;
733 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
734
735 for (ssize_t i=0; i<entryCount; i++) {
736 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
737 block = entry->stringBlock;
738 value = entry->map.value;
739 }
740 entry++;
741 }
742
743 res.unlock();
744
745 if (block < 0) {
746 return block;
747 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 uint32_t ref = ident;
750 if (resolve) {
751 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800752#if THROW_ON_BAD_ID
753 if (block == BAD_INDEX) {
754 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
755 return 0;
756 }
757#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
759 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
760}
761
762static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
763{
764 AssetManager* am = assetManagerForJavaObject(env, clazz);
765 if (am == NULL) {
766 return 0;
767 }
768 return am->getResources().getTableCount();
769}
770
771static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
772 jint block)
773{
774 AssetManager* am = assetManagerForJavaObject(env, clazz);
775 if (am == NULL) {
776 return 0;
777 }
778 return (jint)am->getResources().getTableStringBlock(block);
779}
780
781static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
782 jint cookie)
783{
784 AssetManager* am = assetManagerForJavaObject(env, clazz);
785 if (am == NULL) {
786 return NULL;
787 }
788 String8 name(am->getAssetPath((void*)cookie));
789 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700790 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 return NULL;
792 }
793 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 return str;
795}
796
797static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
798{
799 AssetManager* am = assetManagerForJavaObject(env, clazz);
800 if (am == NULL) {
801 return 0;
802 }
803 return (jint)(new ResTable::Theme(am->getResources()));
804}
805
806static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
807 jint themeInt)
808{
809 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
810 delete theme;
811}
812
813static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
814 jint themeInt,
815 jint styleRes,
816 jboolean force)
817{
818 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
819 theme->applyStyle(styleRes, force ? true : false);
820}
821
822static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
823 jint destInt, jint srcInt)
824{
825 ResTable::Theme* dest = (ResTable::Theme*)destInt;
826 ResTable::Theme* src = (ResTable::Theme*)srcInt;
827 dest->setTo(*src);
828}
829
830static jint android_content_AssetManager_loadThemeAttributeValue(
831 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
832{
833 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
834 const ResTable& res(theme->getResTable());
835
836 Res_value value;
837 // XXX value could be different in different configs!
838 uint32_t typeSpecFlags = 0;
839 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
840 uint32_t ref = 0;
841 if (resolve) {
842 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800843#if THROW_ON_BAD_ID
844 if (block == BAD_INDEX) {
845 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
846 return 0;
847 }
848#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 }
850 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
851}
852
853static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
854 jint themeInt, jint pri,
855 jstring tag, jstring prefix)
856{
857 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
858 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 // XXX Need to use params.
861 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862}
863
864static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
865 jint themeToken,
866 jint defStyleAttr,
867 jint defStyleRes,
868 jint xmlParserToken,
869 jintArray attrs,
870 jintArray outValues,
871 jintArray outIndices)
872{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700873 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700874 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700875 return JNI_FALSE;
876 }
877 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700878 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700879 return JNI_FALSE;
880 }
881 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700882 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return JNI_FALSE;
884 }
885
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800886 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
887 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
890 const ResTable& res = theme->getResTable();
891 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700892 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 Res_value value;
894
895 const jsize NI = env->GetArrayLength(attrs);
896 const jsize NV = env->GetArrayLength(outValues);
897 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700898 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 return JNI_FALSE;
900 }
901
902 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
903 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 return JNI_FALSE;
905 }
906
907 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
908 jint* dest = baseDest;
909 if (dest == NULL) {
910 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 return JNI_FALSE;
912 }
913
914 jint* indices = NULL;
915 int indicesIdx = 0;
916 if (outIndices != NULL) {
917 if (env->GetArrayLength(outIndices) > NI) {
918 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
919 }
920 }
921
922 // Load default style from attribute, if specified...
923 uint32_t defStyleBagTypeSetFlags = 0;
924 if (defStyleAttr != 0) {
925 Res_value value;
926 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
927 if (value.dataType == Res_value::TYPE_REFERENCE) {
928 defStyleRes = value.data;
929 }
930 }
931 }
932
933 // Retrieve the style class associated with the current XML tag.
934 int style = 0;
935 uint32_t styleBagTypeSetFlags = 0;
936 if (xmlParser != NULL) {
937 ssize_t idx = xmlParser->indexOfStyle();
938 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
939 if (value.dataType == value.TYPE_ATTRIBUTE) {
940 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
941 value.dataType = Res_value::TYPE_NULL;
942 }
943 }
944 if (value.dataType == value.TYPE_REFERENCE) {
945 style = value.data;
946 }
947 }
948 }
949
950 // Now lock down the resource object and start pulling stuff from it.
951 res.lock();
952
953 // Retrieve the default style bag, if requested.
954 const ResTable::bag_entry* defStyleEnt = NULL;
955 uint32_t defStyleTypeSetFlags = 0;
956 ssize_t bagOff = defStyleRes != 0
957 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
958 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
959 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
960 (bagOff >= 0 ? bagOff : 0);
961
962 // Retrieve the style class bag, if requested.
963 const ResTable::bag_entry* styleEnt = NULL;
964 uint32_t styleTypeSetFlags = 0;
965 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
966 styleTypeSetFlags |= styleBagTypeSetFlags;
967 const ResTable::bag_entry* endStyleEnt = styleEnt +
968 (bagOff >= 0 ? bagOff : 0);
969
970 // Retrieve the XML attributes, if requested.
971 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
972 jsize ix=0;
973 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
974
975 static const ssize_t kXmlBlock = 0x10000000;
976
977 // Now iterate through all of the attributes that the client has requested,
978 // filling in each with whatever data we can find.
979 ssize_t block = 0;
980 uint32_t typeSetFlags;
981 for (jsize ii=0; ii<NI; ii++) {
982 const uint32_t curIdent = (uint32_t)src[ii];
983
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800984 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 // Try to find a value for this attribute... we prioritize values
987 // coming from, first XML attributes, then XML style, then default
988 // style, and finally the theme.
989 value.dataType = Res_value::TYPE_NULL;
990 value.data = 0;
991 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700992 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993
994 // Skip through XML attributes until the end or the next possible match.
995 while (ix < NX && curIdent > curXmlAttr) {
996 ix++;
997 curXmlAttr = xmlParser->getAttributeNameResID(ix);
998 }
999 // Retrieve the current XML attribute if it matches, and step to next.
1000 if (ix < NX && curIdent == curXmlAttr) {
1001 block = kXmlBlock;
1002 xmlParser->getAttributeValue(ix, &value);
1003 ix++;
1004 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001005 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1006 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008
1009 // Skip through the style values until the end or the next possible match.
1010 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1011 styleEnt++;
1012 }
1013 // Retrieve the current style attribute if it matches, and step to next.
1014 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1015 if (value.dataType == Res_value::TYPE_NULL) {
1016 block = styleEnt->stringBlock;
1017 typeSetFlags = styleTypeSetFlags;
1018 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001019 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1020 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
1022 styleEnt++;
1023 }
1024
1025 // Skip through the default style values until the end or the next possible match.
1026 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1027 defStyleEnt++;
1028 }
1029 // Retrieve the current default style attribute if it matches, and step to next.
1030 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1031 if (value.dataType == Res_value::TYPE_NULL) {
1032 block = defStyleEnt->stringBlock;
1033 typeSetFlags = defStyleTypeSetFlags;
1034 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001035 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1036 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 }
1038 defStyleEnt++;
1039 }
1040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 uint32_t resid = 0;
1042 if (value.dataType != Res_value::TYPE_NULL) {
1043 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001044 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1045 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001047 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1048 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 } else {
1050 // If we still don't have a value for this attribute, try to find
1051 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1053 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001054 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1055 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001056 newBlock = res.resolveReference(&value, block, &resid,
1057 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001058#if THROW_ON_BAD_ID
1059 if (newBlock == BAD_INDEX) {
1060 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1061 return JNI_FALSE;
1062 }
1063#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001065 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1066 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
1069
1070 // Deal with the special @null value -- it turns back to TYPE_NULL.
1071 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001072 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001074 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001077 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1078 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079
1080 // Write the final value back to Java.
1081 dest[STYLE_TYPE] = value.dataType;
1082 dest[STYLE_DATA] = value.data;
1083 dest[STYLE_ASSET_COOKIE] =
1084 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1085 dest[STYLE_RESOURCE_ID] = resid;
1086 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001087 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1090 indicesIdx++;
1091 indices[indicesIdx] = ii;
1092 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 dest += STYLE_NUM_ENTRIES;
1095 }
1096
1097 res.unlock();
1098
1099 if (indices != NULL) {
1100 indices[0] = indicesIdx;
1101 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1102 }
1103 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1104 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1105
1106 return JNI_TRUE;
1107}
1108
1109static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1110 jint xmlParserToken,
1111 jintArray attrs,
1112 jintArray outValues,
1113 jintArray outIndices)
1114{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001115 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001116 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001117 return JNI_FALSE;
1118 }
1119 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001120 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001121 return JNI_FALSE;
1122 }
1123 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001124 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 return JNI_FALSE;
1126 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 AssetManager* am = assetManagerForJavaObject(env, clazz);
1129 if (am == NULL) {
1130 return JNI_FALSE;
1131 }
1132 const ResTable& res(am->getResources());
1133 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001134 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 const jsize NI = env->GetArrayLength(attrs);
1138 const jsize NV = env->GetArrayLength(outValues);
1139 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001140 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 return JNI_FALSE;
1142 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1145 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 return JNI_FALSE;
1147 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1150 jint* dest = baseDest;
1151 if (dest == NULL) {
1152 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 return JNI_FALSE;
1154 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 jint* indices = NULL;
1157 int indicesIdx = 0;
1158 if (outIndices != NULL) {
1159 if (env->GetArrayLength(outIndices) > NI) {
1160 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1161 }
1162 }
1163
1164 // Now lock down the resource object and start pulling stuff from it.
1165 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 // Retrieve the XML attributes, if requested.
1168 const jsize NX = xmlParser->getAttributeCount();
1169 jsize ix=0;
1170 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 // Now iterate through all of the attributes that the client has requested,
1175 // filling in each with whatever data we can find.
1176 ssize_t block = 0;
1177 uint32_t typeSetFlags;
1178 for (jsize ii=0; ii<NI; ii++) {
1179 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 // Try to find a value for this attribute...
1182 value.dataType = Res_value::TYPE_NULL;
1183 value.data = 0;
1184 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001185 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 // Skip through XML attributes until the end or the next possible match.
1188 while (ix < NX && curIdent > curXmlAttr) {
1189 ix++;
1190 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1191 }
1192 // Retrieve the current XML attribute if it matches, and step to next.
1193 if (ix < NX && curIdent == curXmlAttr) {
1194 block = kXmlBlock;
1195 xmlParser->getAttributeValue(ix, &value);
1196 ix++;
1197 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1198 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1201 uint32_t resid = 0;
1202 if (value.dataType != Res_value::TYPE_NULL) {
1203 // Take care of resolving the found resource to its final value.
1204 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001205 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1206 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001207#if THROW_ON_BAD_ID
1208 if (newBlock == BAD_INDEX) {
1209 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1210 return JNI_FALSE;
1211 }
1212#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 if (newBlock >= 0) block = newBlock;
1214 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 // Deal with the special @null value -- it turns back to TYPE_NULL.
1217 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1218 value.dataType = Res_value::TYPE_NULL;
1219 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 // Write the final value back to Java.
1224 dest[STYLE_TYPE] = value.dataType;
1225 dest[STYLE_DATA] = value.data;
1226 dest[STYLE_ASSET_COOKIE] =
1227 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1228 dest[STYLE_RESOURCE_ID] = resid;
1229 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001230 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1233 indicesIdx++;
1234 indices[indicesIdx] = ii;
1235 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 dest += STYLE_NUM_ENTRIES;
1238 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 if (indices != NULL) {
1243 indices[0] = indicesIdx;
1244 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1245 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1248 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 return JNI_TRUE;
1251}
1252
1253static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1254 jint id)
1255{
1256 AssetManager* am = assetManagerForJavaObject(env, clazz);
1257 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001258 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
1260 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 res.lock();
1263 const ResTable::bag_entry* defStyleEnt = NULL;
1264 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1265 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 return bagOff;
1268}
1269
1270static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1271 jint id,
1272 jintArray outValues)
1273{
1274 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001275 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 return JNI_FALSE;
1277 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 AssetManager* am = assetManagerForJavaObject(env, clazz);
1280 if (am == NULL) {
1281 return JNI_FALSE;
1282 }
1283 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001284 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 Res_value value;
1286 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1291 jint* dest = baseDest;
1292 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001293 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 return JNI_FALSE;
1295 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 // Now lock down the resource object and start pulling stuff from it.
1298 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 const ResTable::bag_entry* arrayEnt = NULL;
1301 uint32_t arrayTypeSetFlags = 0;
1302 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1303 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1304 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 int i = 0;
1307 uint32_t typeSetFlags;
1308 while (i < NV && arrayEnt < endArrayEnt) {
1309 block = arrayEnt->stringBlock;
1310 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001311 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 uint32_t resid = 0;
1315 if (value.dataType != Res_value::TYPE_NULL) {
1316 // Take care of resolving the found resource to its final value.
1317 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001318 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1319 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001320#if THROW_ON_BAD_ID
1321 if (newBlock == BAD_INDEX) {
1322 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1323 return JNI_FALSE;
1324 }
1325#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 if (newBlock >= 0) block = newBlock;
1327 }
1328
1329 // Deal with the special @null value -- it turns back to TYPE_NULL.
1330 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1331 value.dataType = Res_value::TYPE_NULL;
1332 }
1333
1334 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1335
1336 // Write the final value back to Java.
1337 dest[STYLE_TYPE] = value.dataType;
1338 dest[STYLE_DATA] = value.data;
1339 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1340 dest[STYLE_RESOURCE_ID] = resid;
1341 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001342 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 dest += STYLE_NUM_ENTRIES;
1344 i+= STYLE_NUM_ENTRIES;
1345 arrayEnt++;
1346 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 return i;
1355}
1356
1357static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1358 jint cookie,
1359 jstring fileName)
1360{
1361 AssetManager* am = assetManagerForJavaObject(env, clazz);
1362 if (am == NULL) {
1363 return 0;
1364 }
1365
1366 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1367
Elliott Hughes69a017b2011-04-08 14:10:28 -07001368 ScopedUtfChars fileName8(env, fileName);
1369 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 return 0;
1371 }
1372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -07001374 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1375 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376
1377 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001378 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 return 0;
1380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381
1382 ResXMLTree* block = new ResXMLTree();
1383 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1384 a->close();
1385 delete a;
1386
1387 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001388 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 return 0;
1390 }
1391
1392 return (jint)block;
1393}
1394
1395static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1396 jint arrayResId)
1397{
1398 AssetManager* am = assetManagerForJavaObject(env, clazz);
1399 if (am == NULL) {
1400 return NULL;
1401 }
1402 const ResTable& res(am->getResources());
1403
1404 const ResTable::bag_entry* startOfBag;
1405 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1406 if (N < 0) {
1407 return NULL;
1408 }
1409
1410 jintArray array = env->NewIntArray(N * 2);
1411 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 res.unlockBag(startOfBag);
1413 return NULL;
1414 }
1415
1416 Res_value value;
1417 const ResTable::bag_entry* bag = startOfBag;
1418 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1419 jint stringIndex = -1;
1420 jint stringBlock = 0;
1421 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 // Take care of resolving the found resource to its final value.
1424 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1425 if (value.dataType == Res_value::TYPE_STRING) {
1426 stringIndex = value.data;
1427 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001428
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001429#if THROW_ON_BAD_ID
1430 if (stringBlock == BAD_INDEX) {
1431 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1432 return array;
1433 }
1434#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 //todo: It might be faster to allocate a C array to contain
1437 // the blocknums and indices, put them in there and then
1438 // do just one SetIntArrayRegion()
1439 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1440 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1441 j = j + 2;
1442 }
1443 res.unlockBag(startOfBag);
1444 return array;
1445}
1446
1447static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1448 jint arrayResId)
1449{
1450 AssetManager* am = assetManagerForJavaObject(env, clazz);
1451 if (am == NULL) {
1452 return NULL;
1453 }
1454 const ResTable& res(am->getResources());
1455
1456 jclass cls = env->FindClass("java/lang/String");
1457 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1458 if (cls == NULL) {
1459 return NULL;
1460 }
1461
1462 const ResTable::bag_entry* startOfBag;
1463 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1464 if (N < 0) {
1465 return NULL;
1466 }
1467
1468 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001469 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 res.unlockBag(startOfBag);
1471 return NULL;
1472 }
1473
1474 Res_value value;
1475 const ResTable::bag_entry* bag = startOfBag;
1476 size_t strLen = 0;
1477 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1478 value = bag->map.value;
1479 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 // Take care of resolving the found resource to its final value.
1482 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001483#if THROW_ON_BAD_ID
1484 if (block == BAD_INDEX) {
1485 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1486 return array;
1487 }
1488#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001490 const ResStringPool* pool = res.getTableStringBlock(block);
1491 const char* str8 = pool->string8At(value.data, &strLen);
1492 if (str8 != NULL) {
1493 str = env->NewStringUTF(str8);
1494 } else {
1495 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1496 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001497 }
1498
1499 // If one of our NewString{UTF} calls failed due to memory, an
1500 // exception will be pending.
1501 if (env->ExceptionCheck()) {
1502 res.unlockBag(startOfBag);
1503 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 }
Kenny Root780d2a12010-02-22 22:36:26 -08001505
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001506 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001507
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001508 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1509 // If we have a large amount of strings in our array, we might
1510 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001511 env->DeleteLocalRef(str);
1512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
1514 res.unlockBag(startOfBag);
1515 return array;
1516}
1517
1518static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1519 jint arrayResId)
1520{
1521 AssetManager* am = assetManagerForJavaObject(env, clazz);
1522 if (am == NULL) {
1523 return NULL;
1524 }
1525 const ResTable& res(am->getResources());
1526
1527 const ResTable::bag_entry* startOfBag;
1528 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1529 if (N < 0) {
1530 return NULL;
1531 }
1532
1533 jintArray array = env->NewIntArray(N);
1534 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 res.unlockBag(startOfBag);
1536 return NULL;
1537 }
1538
1539 Res_value value;
1540 const ResTable::bag_entry* bag = startOfBag;
1541 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1542 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 // Take care of resolving the found resource to its final value.
1545 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001546#if THROW_ON_BAD_ID
1547 if (block == BAD_INDEX) {
1548 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1549 return array;
1550 }
1551#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 if (value.dataType >= Res_value::TYPE_FIRST_INT
1553 && value.dataType <= Res_value::TYPE_LAST_INT) {
1554 int intVal = value.data;
1555 env->SetIntArrayRegion(array, i, 1, &intVal);
1556 }
1557 }
1558 res.unlockBag(startOfBag);
1559 return array;
1560}
1561
1562static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1563{
1564 AssetManager* am = new AssetManager();
1565 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001566 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 return;
1568 }
1569
1570 am->addDefaultAssets();
1571
1572 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1573 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1574}
1575
1576static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1577{
1578 AssetManager* am = (AssetManager*)
1579 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1580 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1581 if (am != NULL) {
1582 delete am;
1583 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1584 }
1585}
1586
1587static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1588{
1589 return Asset::getGlobalCount();
1590}
1591
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001592static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1593{
1594 String8 alloc = Asset::getAssetAllocations();
1595 if (alloc.length() <= 0) {
1596 return NULL;
1597 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001598
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001599 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001600 return str;
1601}
1602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1604{
1605 return AssetManager::getGlobalCount();
1606}
1607
1608// ----------------------------------------------------------------------------
1609
1610/*
1611 * JNI registration.
1612 */
1613static JNINativeMethod gAssetManagerMethods[] = {
1614 /* name, signature, funcPtr */
1615
1616 // Basic asset stuff.
1617 { "openAsset", "(Ljava/lang/String;I)I",
1618 (void*) android_content_AssetManager_openAsset },
1619 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1620 (void*) android_content_AssetManager_openAssetFd },
1621 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1622 (void*) android_content_AssetManager_openNonAssetNative },
1623 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1624 (void*) android_content_AssetManager_openNonAssetFdNative },
1625 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1626 (void*) android_content_AssetManager_list },
1627 { "destroyAsset", "(I)V",
1628 (void*) android_content_AssetManager_destroyAsset },
1629 { "readAssetChar", "(I)I",
1630 (void*) android_content_AssetManager_readAssetChar },
1631 { "readAsset", "(I[BII)I",
1632 (void*) android_content_AssetManager_readAsset },
1633 { "seekAsset", "(IJI)J",
1634 (void*) android_content_AssetManager_seekAsset },
1635 { "getAssetLength", "(I)J",
1636 (void*) android_content_AssetManager_getAssetLength },
1637 { "getAssetRemainingLength", "(I)J",
1638 (void*) android_content_AssetManager_getAssetRemainingLength },
1639 { "addAssetPath", "(Ljava/lang/String;)I",
1640 (void*) android_content_AssetManager_addAssetPath },
1641 { "isUpToDate", "()Z",
1642 (void*) android_content_AssetManager_isUpToDate },
1643
1644 // Resources.
1645 { "setLocale", "(Ljava/lang/String;)V",
1646 (void*) android_content_AssetManager_setLocale },
1647 { "getLocales", "()[Ljava/lang/String;",
1648 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn3fc982f2011-03-30 16:20:26 -07001649 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 (void*) android_content_AssetManager_setConfiguration },
1651 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1652 (void*) android_content_AssetManager_getResourceIdentifier },
1653 { "getResourceName","(I)Ljava/lang/String;",
1654 (void*) android_content_AssetManager_getResourceName },
1655 { "getResourcePackageName","(I)Ljava/lang/String;",
1656 (void*) android_content_AssetManager_getResourcePackageName },
1657 { "getResourceTypeName","(I)Ljava/lang/String;",
1658 (void*) android_content_AssetManager_getResourceTypeName },
1659 { "getResourceEntryName","(I)Ljava/lang/String;",
1660 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001661 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 (void*) android_content_AssetManager_loadResourceValue },
1663 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1664 (void*) android_content_AssetManager_loadResourceBagValue },
1665 { "getStringBlockCount","()I",
1666 (void*) android_content_AssetManager_getStringBlockCount },
1667 { "getNativeStringBlock","(I)I",
1668 (void*) android_content_AssetManager_getNativeStringBlock },
1669 { "getCookieName","(I)Ljava/lang/String;",
1670 (void*) android_content_AssetManager_getCookieName },
1671
1672 // Themes.
1673 { "newTheme", "()I",
1674 (void*) android_content_AssetManager_newTheme },
1675 { "deleteTheme", "(I)V",
1676 (void*) android_content_AssetManager_deleteTheme },
1677 { "applyThemeStyle", "(IIZ)V",
1678 (void*) android_content_AssetManager_applyThemeStyle },
1679 { "copyTheme", "(II)V",
1680 (void*) android_content_AssetManager_copyTheme },
1681 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1682 (void*) android_content_AssetManager_loadThemeAttributeValue },
1683 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1684 (void*) android_content_AssetManager_dumpTheme },
1685 { "applyStyle","(IIII[I[I[I)Z",
1686 (void*) android_content_AssetManager_applyStyle },
1687 { "retrieveAttributes","(I[I[I[I)Z",
1688 (void*) android_content_AssetManager_retrieveAttributes },
1689 { "getArraySize","(I)I",
1690 (void*) android_content_AssetManager_getArraySize },
1691 { "retrieveArray","(I[I)I",
1692 (void*) android_content_AssetManager_retrieveArray },
1693
1694 // XML files.
1695 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1696 (void*) android_content_AssetManager_openXmlAssetNative },
1697
1698 // Arrays.
1699 { "getArrayStringResource","(I)[Ljava/lang/String;",
1700 (void*) android_content_AssetManager_getArrayStringResource },
1701 { "getArrayStringInfo","(I)[I",
1702 (void*) android_content_AssetManager_getArrayStringInfo },
1703 { "getArrayIntResource","(I)[I",
1704 (void*) android_content_AssetManager_getArrayIntResource },
1705
1706 // Bookkeeping.
1707 { "init", "()V",
1708 (void*) android_content_AssetManager_init },
1709 { "destroy", "()V",
1710 (void*) android_content_AssetManager_destroy },
1711 { "getGlobalAssetCount", "()I",
1712 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001713 { "getAssetAllocations", "()Ljava/lang/String;",
1714 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 { "getGlobalAssetManagerCount", "()I",
1716 (void*) android_content_AssetManager_getGlobalAssetCount },
1717};
1718
1719int register_android_content_AssetManager(JNIEnv* env)
1720{
1721 jclass typedValue = env->FindClass("android/util/TypedValue");
1722 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1723 gTypedValueOffsets.mType
1724 = env->GetFieldID(typedValue, "type", "I");
1725 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1726 gTypedValueOffsets.mData
1727 = env->GetFieldID(typedValue, "data", "I");
1728 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1729 gTypedValueOffsets.mString
1730 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1731 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1732 gTypedValueOffsets.mAssetCookie
1733 = env->GetFieldID(typedValue, "assetCookie", "I");
1734 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1735 gTypedValueOffsets.mResourceId
1736 = env->GetFieldID(typedValue, "resourceId", "I");
1737 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1738 gTypedValueOffsets.mChangingConfigurations
1739 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1740 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1741 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1742 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1743
1744 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1745 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1746 gAssetFileDescriptorOffsets.mFd
1747 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1748 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1749 gAssetFileDescriptorOffsets.mStartOffset
1750 = env->GetFieldID(assetFd, "mStartOffset", "J");
1751 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1752 gAssetFileDescriptorOffsets.mLength
1753 = env->GetFieldID(assetFd, "mLength", "J");
1754 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1755
1756 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1757 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1758 gAssetManagerOffsets.mObject
1759 = env->GetFieldID(assetManager, "mObject", "I");
1760 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1761
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001762 jclass stringClass = env->FindClass("java/lang/String");
1763 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1764 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765
1766 return AndroidRuntime::registerNativeMethods(env,
1767 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1768}
1769
1770}; // namespace android