blob: 785bf132e2959a6223601530d6c2e19089a4aad0 [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
Mathias Agopianb13b9bd2012-02-17 18:27:36 -080034#include <androidfw/Asset.h>
35#include <androidfw/AssetManager.h>
36#include <androidfw/ResourceTypes.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
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
Steve Block71f2cf12011-10-20 11:56:00 +0100124 ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
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
Steve Block71f2cf12011-10-20 11:56:00 +0100189 ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
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
Steve Block71f2cf12011-10-20 11:56:00 +0100218 ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
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
Steve Block71f2cf12011-10-20 11:56:00 +0100255 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
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) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800437 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
439
440 AssetManager* am = assetManagerForJavaObject(env, clazz);
441 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800442 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
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 Hackborn69cb8752011-05-19 18:13:32 -0700513 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700514 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100515 jint screenLayout, jint uiMode,
516 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517{
518 AssetManager* am = assetManagerForJavaObject(env, clazz);
519 if (am == NULL) {
520 return;
521 }
522
523 ResTable_config config;
524 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 config.mcc = (uint16_t)mcc;
529 config.mnc = (uint16_t)mnc;
530 config.orientation = (uint8_t)orientation;
531 config.touchscreen = (uint8_t)touchscreen;
532 config.density = (uint16_t)density;
533 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700534 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 config.navigation = (uint8_t)navigation;
536 config.screenWidth = (uint16_t)screenWidth;
537 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700538 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700539 config.screenWidthDp = (uint16_t)screenWidthDp;
540 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700541 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100542 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 config.sdkVersion = (uint16_t)sdkVersion;
544 config.minorVersion = 0;
545 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
548}
549
550static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
551 jstring name,
552 jstring defType,
553 jstring defPackage)
554{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700555 ScopedStringChars name16(env, name);
556 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 return 0;
558 }
559
560 AssetManager* am = assetManagerForJavaObject(env, clazz);
561 if (am == NULL) {
562 return 0;
563 }
564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 const char16_t* defType16 = defType
566 ? env->GetStringChars(defType, NULL) : NULL;
567 jsize defTypeLen = defType
568 ? env->GetStringLength(defType) : 0;
569 const char16_t* defPackage16 = defPackage
570 ? env->GetStringChars(defPackage, NULL) : NULL;
571 jsize defPackageLen = defPackage
572 ? env->GetStringLength(defPackage) : 0;
573
574 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700575 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
577 if (defPackage16) {
578 env->ReleaseStringChars(defPackage, defPackage16);
579 }
580 if (defType16) {
581 env->ReleaseStringChars(defType, defType16);
582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583
584 return ident;
585}
586
587static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
588 jint resid)
589{
590 AssetManager* am = assetManagerForJavaObject(env, clazz);
591 if (am == NULL) {
592 return NULL;
593 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 ResTable::resource_name name;
596 if (!am->getResources().getResourceName(resid, &name)) {
597 return NULL;
598 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 String16 str;
601 if (name.package != NULL) {
602 str.setTo(name.package, name.packageLen);
603 }
604 if (name.type != NULL) {
605 if (str.size() > 0) {
606 char16_t div = ':';
607 str.append(&div, 1);
608 }
609 str.append(name.type, name.typeLen);
610 }
611 if (name.name != NULL) {
612 if (str.size() > 0) {
613 char16_t div = '/';
614 str.append(&div, 1);
615 }
616 str.append(name.name, name.nameLen);
617 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 return env->NewString((const jchar*)str.string(), str.size());
620}
621
622static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
623 jint resid)
624{
625 AssetManager* am = assetManagerForJavaObject(env, clazz);
626 if (am == NULL) {
627 return NULL;
628 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 ResTable::resource_name name;
631 if (!am->getResources().getResourceName(resid, &name)) {
632 return NULL;
633 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 if (name.package != NULL) {
636 return env->NewString((const jchar*)name.package, name.packageLen);
637 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 return NULL;
640}
641
642static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
643 jint resid)
644{
645 AssetManager* am = assetManagerForJavaObject(env, clazz);
646 if (am == NULL) {
647 return NULL;
648 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 ResTable::resource_name name;
651 if (!am->getResources().getResourceName(resid, &name)) {
652 return NULL;
653 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 if (name.type != NULL) {
656 return env->NewString((const jchar*)name.type, name.typeLen);
657 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 return NULL;
660}
661
662static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
663 jint resid)
664{
665 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 if (am == NULL) {
667 return NULL;
668 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 ResTable::resource_name name;
671 if (!am->getResources().getResourceName(resid, &name)) {
672 return NULL;
673 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 if (name.name != NULL) {
676 return env->NewString((const jchar*)name.name, name.nameLen);
677 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 return NULL;
680}
681
682static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
683 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700684 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 jobject outValue,
686 jboolean resolve)
687{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800688 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800689 jniThrowNullPointerException(env, "outValue");
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800690 return NULL;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 AssetManager* am = assetManagerForJavaObject(env, clazz);
693 if (am == NULL) {
694 return 0;
695 }
696 const ResTable& res(am->getResources());
697
698 Res_value value;
699 ResTable_config config;
700 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700701 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800702#if THROW_ON_BAD_ID
703 if (block == BAD_INDEX) {
704 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
705 return 0;
706 }
707#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 uint32_t ref = ident;
709 if (resolve) {
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700710 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800711#if THROW_ON_BAD_ID
712 if (block == BAD_INDEX) {
713 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
714 return 0;
715 }
716#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 }
718 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
719}
720
721static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
722 jint ident, jint bagEntryId,
723 jobject outValue, jboolean resolve)
724{
725 AssetManager* am = assetManagerForJavaObject(env, clazz);
726 if (am == NULL) {
727 return 0;
728 }
729 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 // Now lock down the resource object and start pulling stuff from it.
732 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 ssize_t block = -1;
735 Res_value value;
736
737 const ResTable::bag_entry* entry = NULL;
738 uint32_t typeSpecFlags;
739 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
740
741 for (ssize_t i=0; i<entryCount; i++) {
742 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
743 block = entry->stringBlock;
744 value = entry->map.value;
745 }
746 entry++;
747 }
748
749 res.unlock();
750
751 if (block < 0) {
752 return block;
753 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 uint32_t ref = ident;
756 if (resolve) {
757 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800758#if THROW_ON_BAD_ID
759 if (block == BAD_INDEX) {
760 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
761 return 0;
762 }
763#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
766}
767
768static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
769{
770 AssetManager* am = assetManagerForJavaObject(env, clazz);
771 if (am == NULL) {
772 return 0;
773 }
774 return am->getResources().getTableCount();
775}
776
777static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
778 jint block)
779{
780 AssetManager* am = assetManagerForJavaObject(env, clazz);
781 if (am == NULL) {
782 return 0;
783 }
784 return (jint)am->getResources().getTableStringBlock(block);
785}
786
787static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
788 jint cookie)
789{
790 AssetManager* am = assetManagerForJavaObject(env, clazz);
791 if (am == NULL) {
792 return NULL;
793 }
794 String8 name(am->getAssetPath((void*)cookie));
795 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700796 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 return NULL;
798 }
799 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 return str;
801}
802
803static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
804{
805 AssetManager* am = assetManagerForJavaObject(env, clazz);
806 if (am == NULL) {
807 return 0;
808 }
809 return (jint)(new ResTable::Theme(am->getResources()));
810}
811
812static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
813 jint themeInt)
814{
815 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
816 delete theme;
817}
818
819static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
820 jint themeInt,
821 jint styleRes,
822 jboolean force)
823{
824 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
825 theme->applyStyle(styleRes, force ? true : false);
826}
827
828static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
829 jint destInt, jint srcInt)
830{
831 ResTable::Theme* dest = (ResTable::Theme*)destInt;
832 ResTable::Theme* src = (ResTable::Theme*)srcInt;
833 dest->setTo(*src);
834}
835
836static jint android_content_AssetManager_loadThemeAttributeValue(
837 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
838{
839 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
840 const ResTable& res(theme->getResTable());
841
842 Res_value value;
843 // XXX value could be different in different configs!
844 uint32_t typeSpecFlags = 0;
845 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
846 uint32_t ref = 0;
847 if (resolve) {
848 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800849#if THROW_ON_BAD_ID
850 if (block == BAD_INDEX) {
851 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
852 return 0;
853 }
854#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
856 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
857}
858
859static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
860 jint themeInt, jint pri,
861 jstring tag, jstring prefix)
862{
863 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
864 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 // XXX Need to use params.
867 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868}
869
870static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
871 jint themeToken,
872 jint defStyleAttr,
873 jint defStyleRes,
874 jint xmlParserToken,
875 jintArray attrs,
876 jintArray outValues,
877 jintArray outIndices)
878{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700879 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700880 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700881 return JNI_FALSE;
882 }
883 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700884 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700885 return JNI_FALSE;
886 }
887 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700888 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 return JNI_FALSE;
890 }
891
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800892 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
893 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
896 const ResTable& res = theme->getResTable();
897 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700898 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 Res_value value;
900
901 const jsize NI = env->GetArrayLength(attrs);
902 const jsize NV = env->GetArrayLength(outValues);
903 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700904 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 return JNI_FALSE;
906 }
907
908 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
909 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 return JNI_FALSE;
911 }
912
913 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
914 jint* dest = baseDest;
915 if (dest == NULL) {
916 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 return JNI_FALSE;
918 }
919
920 jint* indices = NULL;
921 int indicesIdx = 0;
922 if (outIndices != NULL) {
923 if (env->GetArrayLength(outIndices) > NI) {
924 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
925 }
926 }
927
928 // Load default style from attribute, if specified...
929 uint32_t defStyleBagTypeSetFlags = 0;
930 if (defStyleAttr != 0) {
931 Res_value value;
932 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
933 if (value.dataType == Res_value::TYPE_REFERENCE) {
934 defStyleRes = value.data;
935 }
936 }
937 }
938
939 // Retrieve the style class associated with the current XML tag.
940 int style = 0;
941 uint32_t styleBagTypeSetFlags = 0;
942 if (xmlParser != NULL) {
943 ssize_t idx = xmlParser->indexOfStyle();
944 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
945 if (value.dataType == value.TYPE_ATTRIBUTE) {
946 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
947 value.dataType = Res_value::TYPE_NULL;
948 }
949 }
950 if (value.dataType == value.TYPE_REFERENCE) {
951 style = value.data;
952 }
953 }
954 }
955
956 // Now lock down the resource object and start pulling stuff from it.
957 res.lock();
958
959 // Retrieve the default style bag, if requested.
960 const ResTable::bag_entry* defStyleEnt = NULL;
961 uint32_t defStyleTypeSetFlags = 0;
962 ssize_t bagOff = defStyleRes != 0
963 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
964 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
965 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
966 (bagOff >= 0 ? bagOff : 0);
967
968 // Retrieve the style class bag, if requested.
969 const ResTable::bag_entry* styleEnt = NULL;
970 uint32_t styleTypeSetFlags = 0;
971 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
972 styleTypeSetFlags |= styleBagTypeSetFlags;
973 const ResTable::bag_entry* endStyleEnt = styleEnt +
974 (bagOff >= 0 ? bagOff : 0);
975
976 // Retrieve the XML attributes, if requested.
977 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
978 jsize ix=0;
979 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
980
981 static const ssize_t kXmlBlock = 0x10000000;
982
983 // Now iterate through all of the attributes that the client has requested,
984 // filling in each with whatever data we can find.
985 ssize_t block = 0;
986 uint32_t typeSetFlags;
987 for (jsize ii=0; ii<NI; ii++) {
988 const uint32_t curIdent = (uint32_t)src[ii];
989
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800990 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 // Try to find a value for this attribute... we prioritize values
993 // coming from, first XML attributes, then XML style, then default
994 // style, and finally the theme.
995 value.dataType = Res_value::TYPE_NULL;
996 value.data = 0;
997 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700998 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999
1000 // Skip through XML attributes until the end or the next possible match.
1001 while (ix < NX && curIdent > curXmlAttr) {
1002 ix++;
1003 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1004 }
1005 // Retrieve the current XML attribute if it matches, and step to next.
1006 if (ix < NX && curIdent == curXmlAttr) {
1007 block = kXmlBlock;
1008 xmlParser->getAttributeValue(ix, &value);
1009 ix++;
1010 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001011 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1012 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 }
1014
1015 // Skip through the style values until the end or the next possible match.
1016 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1017 styleEnt++;
1018 }
1019 // Retrieve the current style attribute if it matches, and step to next.
1020 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1021 if (value.dataType == Res_value::TYPE_NULL) {
1022 block = styleEnt->stringBlock;
1023 typeSetFlags = styleTypeSetFlags;
1024 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001025 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1026 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 }
1028 styleEnt++;
1029 }
1030
1031 // Skip through the default style values until the end or the next possible match.
1032 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1033 defStyleEnt++;
1034 }
1035 // Retrieve the current default style attribute if it matches, and step to next.
1036 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1037 if (value.dataType == Res_value::TYPE_NULL) {
1038 block = defStyleEnt->stringBlock;
1039 typeSetFlags = defStyleTypeSetFlags;
1040 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001041 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1042 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
1044 defStyleEnt++;
1045 }
1046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 uint32_t resid = 0;
1048 if (value.dataType != Res_value::TYPE_NULL) {
1049 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001050 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1051 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001053 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1054 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 } else {
1056 // If we still don't have a value for this attribute, try to find
1057 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1059 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001060 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1061 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001062 newBlock = res.resolveReference(&value, block, &resid,
1063 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001064#if THROW_ON_BAD_ID
1065 if (newBlock == BAD_INDEX) {
1066 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1067 return JNI_FALSE;
1068 }
1069#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001071 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1072 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
1074 }
1075
1076 // Deal with the special @null value -- it turns back to TYPE_NULL.
1077 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001078 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001080 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 }
1082
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001083 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1084 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085
1086 // Write the final value back to Java.
1087 dest[STYLE_TYPE] = value.dataType;
1088 dest[STYLE_DATA] = value.data;
1089 dest[STYLE_ASSET_COOKIE] =
1090 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1091 dest[STYLE_RESOURCE_ID] = resid;
1092 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001093 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1096 indicesIdx++;
1097 indices[indicesIdx] = ii;
1098 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 dest += STYLE_NUM_ENTRIES;
1101 }
1102
1103 res.unlock();
1104
1105 if (indices != NULL) {
1106 indices[0] = indicesIdx;
1107 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1108 }
1109 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1110 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1111
1112 return JNI_TRUE;
1113}
1114
1115static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1116 jint xmlParserToken,
1117 jintArray attrs,
1118 jintArray outValues,
1119 jintArray outIndices)
1120{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001121 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001122 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001123 return JNI_FALSE;
1124 }
1125 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001126 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001127 return JNI_FALSE;
1128 }
1129 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001130 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 return JNI_FALSE;
1132 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 AssetManager* am = assetManagerForJavaObject(env, clazz);
1135 if (am == NULL) {
1136 return JNI_FALSE;
1137 }
1138 const ResTable& res(am->getResources());
1139 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001140 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 const jsize NI = env->GetArrayLength(attrs);
1144 const jsize NV = env->GetArrayLength(outValues);
1145 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001146 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 return JNI_FALSE;
1148 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1151 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 return JNI_FALSE;
1153 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1156 jint* dest = baseDest;
1157 if (dest == NULL) {
1158 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 return JNI_FALSE;
1160 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 jint* indices = NULL;
1163 int indicesIdx = 0;
1164 if (outIndices != NULL) {
1165 if (env->GetArrayLength(outIndices) > NI) {
1166 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1167 }
1168 }
1169
1170 // Now lock down the resource object and start pulling stuff from it.
1171 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 // Retrieve the XML attributes, if requested.
1174 const jsize NX = xmlParser->getAttributeCount();
1175 jsize ix=0;
1176 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 // Now iterate through all of the attributes that the client has requested,
1181 // filling in each with whatever data we can find.
1182 ssize_t block = 0;
1183 uint32_t typeSetFlags;
1184 for (jsize ii=0; ii<NI; ii++) {
1185 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 // Try to find a value for this attribute...
1188 value.dataType = Res_value::TYPE_NULL;
1189 value.data = 0;
1190 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001191 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 // Skip through XML attributes until the end or the next possible match.
1194 while (ix < NX && curIdent > curXmlAttr) {
1195 ix++;
1196 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1197 }
1198 // Retrieve the current XML attribute if it matches, and step to next.
1199 if (ix < NX && curIdent == curXmlAttr) {
1200 block = kXmlBlock;
1201 xmlParser->getAttributeValue(ix, &value);
1202 ix++;
1203 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1204 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1207 uint32_t resid = 0;
1208 if (value.dataType != Res_value::TYPE_NULL) {
1209 // Take care of resolving the found resource to its final value.
1210 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001211 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1212 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001213#if THROW_ON_BAD_ID
1214 if (newBlock == BAD_INDEX) {
1215 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1216 return JNI_FALSE;
1217 }
1218#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 if (newBlock >= 0) block = newBlock;
1220 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 // Deal with the special @null value -- it turns back to TYPE_NULL.
1223 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1224 value.dataType = Res_value::TYPE_NULL;
1225 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 // Write the final value back to Java.
1230 dest[STYLE_TYPE] = value.dataType;
1231 dest[STYLE_DATA] = value.data;
1232 dest[STYLE_ASSET_COOKIE] =
1233 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1234 dest[STYLE_RESOURCE_ID] = resid;
1235 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001236 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1239 indicesIdx++;
1240 indices[indicesIdx] = ii;
1241 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 dest += STYLE_NUM_ENTRIES;
1244 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 if (indices != NULL) {
1249 indices[0] = indicesIdx;
1250 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1251 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1254 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 return JNI_TRUE;
1257}
1258
1259static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1260 jint id)
1261{
1262 AssetManager* am = assetManagerForJavaObject(env, clazz);
1263 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001264 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 res.lock();
1269 const ResTable::bag_entry* defStyleEnt = NULL;
1270 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1271 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 return bagOff;
1274}
1275
1276static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1277 jint id,
1278 jintArray outValues)
1279{
1280 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001281 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 return JNI_FALSE;
1283 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 AssetManager* am = assetManagerForJavaObject(env, clazz);
1286 if (am == NULL) {
1287 return JNI_FALSE;
1288 }
1289 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001290 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 Res_value value;
1292 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1297 jint* dest = baseDest;
1298 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001299 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 return JNI_FALSE;
1301 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 // Now lock down the resource object and start pulling stuff from it.
1304 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 const ResTable::bag_entry* arrayEnt = NULL;
1307 uint32_t arrayTypeSetFlags = 0;
1308 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1309 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1310 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 int i = 0;
1313 uint32_t typeSetFlags;
1314 while (i < NV && arrayEnt < endArrayEnt) {
1315 block = arrayEnt->stringBlock;
1316 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001317 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 uint32_t resid = 0;
1321 if (value.dataType != Res_value::TYPE_NULL) {
1322 // Take care of resolving the found resource to its final value.
1323 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001324 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1325 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001326#if THROW_ON_BAD_ID
1327 if (newBlock == BAD_INDEX) {
1328 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1329 return JNI_FALSE;
1330 }
1331#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 if (newBlock >= 0) block = newBlock;
1333 }
1334
1335 // Deal with the special @null value -- it turns back to TYPE_NULL.
1336 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1337 value.dataType = Res_value::TYPE_NULL;
1338 }
1339
1340 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1341
1342 // Write the final value back to Java.
1343 dest[STYLE_TYPE] = value.dataType;
1344 dest[STYLE_DATA] = value.data;
1345 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1346 dest[STYLE_RESOURCE_ID] = resid;
1347 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001348 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 dest += STYLE_NUM_ENTRIES;
1350 i+= STYLE_NUM_ENTRIES;
1351 arrayEnt++;
1352 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 return i;
1361}
1362
1363static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1364 jint cookie,
1365 jstring fileName)
1366{
1367 AssetManager* am = assetManagerForJavaObject(env, clazz);
1368 if (am == NULL) {
1369 return 0;
1370 }
1371
Steve Block71f2cf12011-10-20 11:56:00 +01001372 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373
Elliott Hughes69a017b2011-04-08 14:10:28 -07001374 ScopedUtfChars fileName8(env, fileName);
1375 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 return 0;
1377 }
1378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -07001380 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1381 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382
1383 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001384 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 return 0;
1386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387
1388 ResXMLTree* block = new ResXMLTree();
1389 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1390 a->close();
1391 delete a;
1392
1393 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001394 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 return 0;
1396 }
1397
1398 return (jint)block;
1399}
1400
1401static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1402 jint arrayResId)
1403{
1404 AssetManager* am = assetManagerForJavaObject(env, clazz);
1405 if (am == NULL) {
1406 return NULL;
1407 }
1408 const ResTable& res(am->getResources());
1409
1410 const ResTable::bag_entry* startOfBag;
1411 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1412 if (N < 0) {
1413 return NULL;
1414 }
1415
1416 jintArray array = env->NewIntArray(N * 2);
1417 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 res.unlockBag(startOfBag);
1419 return NULL;
1420 }
1421
1422 Res_value value;
1423 const ResTable::bag_entry* bag = startOfBag;
1424 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1425 jint stringIndex = -1;
1426 jint stringBlock = 0;
1427 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 // Take care of resolving the found resource to its final value.
1430 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1431 if (value.dataType == Res_value::TYPE_STRING) {
1432 stringIndex = value.data;
1433 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001434
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001435#if THROW_ON_BAD_ID
1436 if (stringBlock == BAD_INDEX) {
1437 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1438 return array;
1439 }
1440#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 //todo: It might be faster to allocate a C array to contain
1443 // the blocknums and indices, put them in there and then
1444 // do just one SetIntArrayRegion()
1445 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1446 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1447 j = j + 2;
1448 }
1449 res.unlockBag(startOfBag);
1450 return array;
1451}
1452
1453static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1454 jint arrayResId)
1455{
1456 AssetManager* am = assetManagerForJavaObject(env, clazz);
1457 if (am == NULL) {
1458 return NULL;
1459 }
1460 const ResTable& res(am->getResources());
1461
1462 jclass cls = env->FindClass("java/lang/String");
1463 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1464 if (cls == NULL) {
1465 return NULL;
1466 }
1467
1468 const ResTable::bag_entry* startOfBag;
1469 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1470 if (N < 0) {
1471 return NULL;
1472 }
1473
1474 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001475 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 res.unlockBag(startOfBag);
1477 return NULL;
1478 }
1479
1480 Res_value value;
1481 const ResTable::bag_entry* bag = startOfBag;
1482 size_t strLen = 0;
1483 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1484 value = bag->map.value;
1485 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 // Take care of resolving the found resource to its final value.
1488 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001489#if THROW_ON_BAD_ID
1490 if (block == BAD_INDEX) {
1491 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1492 return array;
1493 }
1494#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001496 const ResStringPool* pool = res.getTableStringBlock(block);
1497 const char* str8 = pool->string8At(value.data, &strLen);
1498 if (str8 != NULL) {
1499 str = env->NewStringUTF(str8);
1500 } else {
1501 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1502 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001503 }
1504
1505 // If one of our NewString{UTF} calls failed due to memory, an
1506 // exception will be pending.
1507 if (env->ExceptionCheck()) {
1508 res.unlockBag(startOfBag);
1509 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 }
Kenny Root780d2a12010-02-22 22:36:26 -08001511
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001512 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001513
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001514 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1515 // If we have a large amount of strings in our array, we might
1516 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001517 env->DeleteLocalRef(str);
1518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 }
1520 res.unlockBag(startOfBag);
1521 return array;
1522}
1523
1524static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1525 jint arrayResId)
1526{
1527 AssetManager* am = assetManagerForJavaObject(env, clazz);
1528 if (am == NULL) {
1529 return NULL;
1530 }
1531 const ResTable& res(am->getResources());
1532
1533 const ResTable::bag_entry* startOfBag;
1534 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1535 if (N < 0) {
1536 return NULL;
1537 }
1538
1539 jintArray array = env->NewIntArray(N);
1540 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 res.unlockBag(startOfBag);
1542 return NULL;
1543 }
1544
1545 Res_value value;
1546 const ResTable::bag_entry* bag = startOfBag;
1547 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1548 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 // Take care of resolving the found resource to its final value.
1551 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001552#if THROW_ON_BAD_ID
1553 if (block == BAD_INDEX) {
1554 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1555 return array;
1556 }
1557#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 if (value.dataType >= Res_value::TYPE_FIRST_INT
1559 && value.dataType <= Res_value::TYPE_LAST_INT) {
1560 int intVal = value.data;
1561 env->SetIntArrayRegion(array, i, 1, &intVal);
1562 }
1563 }
1564 res.unlockBag(startOfBag);
1565 return array;
1566}
1567
1568static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1569{
1570 AssetManager* am = new AssetManager();
1571 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001572 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 return;
1574 }
1575
1576 am->addDefaultAssets();
1577
Steve Block71f2cf12011-10-20 11:56:00 +01001578 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1580}
1581
1582static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1583{
1584 AssetManager* am = (AssetManager*)
1585 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001586 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 if (am != NULL) {
1588 delete am;
1589 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1590 }
1591}
1592
1593static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1594{
1595 return Asset::getGlobalCount();
1596}
1597
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001598static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1599{
1600 String8 alloc = Asset::getAssetAllocations();
1601 if (alloc.length() <= 0) {
1602 return NULL;
1603 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001604
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001605 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001606 return str;
1607}
1608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1610{
1611 return AssetManager::getGlobalCount();
1612}
1613
1614// ----------------------------------------------------------------------------
1615
1616/*
1617 * JNI registration.
1618 */
1619static JNINativeMethod gAssetManagerMethods[] = {
1620 /* name, signature, funcPtr */
1621
1622 // Basic asset stuff.
1623 { "openAsset", "(Ljava/lang/String;I)I",
1624 (void*) android_content_AssetManager_openAsset },
1625 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1626 (void*) android_content_AssetManager_openAssetFd },
1627 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1628 (void*) android_content_AssetManager_openNonAssetNative },
1629 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1630 (void*) android_content_AssetManager_openNonAssetFdNative },
1631 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1632 (void*) android_content_AssetManager_list },
1633 { "destroyAsset", "(I)V",
1634 (void*) android_content_AssetManager_destroyAsset },
1635 { "readAssetChar", "(I)I",
1636 (void*) android_content_AssetManager_readAssetChar },
1637 { "readAsset", "(I[BII)I",
1638 (void*) android_content_AssetManager_readAsset },
1639 { "seekAsset", "(IJI)J",
1640 (void*) android_content_AssetManager_seekAsset },
1641 { "getAssetLength", "(I)J",
1642 (void*) android_content_AssetManager_getAssetLength },
1643 { "getAssetRemainingLength", "(I)J",
1644 (void*) android_content_AssetManager_getAssetRemainingLength },
1645 { "addAssetPath", "(Ljava/lang/String;)I",
1646 (void*) android_content_AssetManager_addAssetPath },
1647 { "isUpToDate", "()Z",
1648 (void*) android_content_AssetManager_isUpToDate },
1649
1650 // Resources.
1651 { "setLocale", "(Ljava/lang/String;)V",
1652 (void*) android_content_AssetManager_setLocale },
1653 { "getLocales", "()[Ljava/lang/String;",
1654 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001655 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 (void*) android_content_AssetManager_setConfiguration },
1657 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1658 (void*) android_content_AssetManager_getResourceIdentifier },
1659 { "getResourceName","(I)Ljava/lang/String;",
1660 (void*) android_content_AssetManager_getResourceName },
1661 { "getResourcePackageName","(I)Ljava/lang/String;",
1662 (void*) android_content_AssetManager_getResourcePackageName },
1663 { "getResourceTypeName","(I)Ljava/lang/String;",
1664 (void*) android_content_AssetManager_getResourceTypeName },
1665 { "getResourceEntryName","(I)Ljava/lang/String;",
1666 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001667 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 (void*) android_content_AssetManager_loadResourceValue },
1669 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1670 (void*) android_content_AssetManager_loadResourceBagValue },
1671 { "getStringBlockCount","()I",
1672 (void*) android_content_AssetManager_getStringBlockCount },
1673 { "getNativeStringBlock","(I)I",
1674 (void*) android_content_AssetManager_getNativeStringBlock },
1675 { "getCookieName","(I)Ljava/lang/String;",
1676 (void*) android_content_AssetManager_getCookieName },
1677
1678 // Themes.
1679 { "newTheme", "()I",
1680 (void*) android_content_AssetManager_newTheme },
1681 { "deleteTheme", "(I)V",
1682 (void*) android_content_AssetManager_deleteTheme },
1683 { "applyThemeStyle", "(IIZ)V",
1684 (void*) android_content_AssetManager_applyThemeStyle },
1685 { "copyTheme", "(II)V",
1686 (void*) android_content_AssetManager_copyTheme },
1687 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1688 (void*) android_content_AssetManager_loadThemeAttributeValue },
1689 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1690 (void*) android_content_AssetManager_dumpTheme },
1691 { "applyStyle","(IIII[I[I[I)Z",
1692 (void*) android_content_AssetManager_applyStyle },
1693 { "retrieveAttributes","(I[I[I[I)Z",
1694 (void*) android_content_AssetManager_retrieveAttributes },
1695 { "getArraySize","(I)I",
1696 (void*) android_content_AssetManager_getArraySize },
1697 { "retrieveArray","(I[I)I",
1698 (void*) android_content_AssetManager_retrieveArray },
1699
1700 // XML files.
1701 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1702 (void*) android_content_AssetManager_openXmlAssetNative },
1703
1704 // Arrays.
1705 { "getArrayStringResource","(I)[Ljava/lang/String;",
1706 (void*) android_content_AssetManager_getArrayStringResource },
1707 { "getArrayStringInfo","(I)[I",
1708 (void*) android_content_AssetManager_getArrayStringInfo },
1709 { "getArrayIntResource","(I)[I",
1710 (void*) android_content_AssetManager_getArrayIntResource },
1711
1712 // Bookkeeping.
1713 { "init", "()V",
1714 (void*) android_content_AssetManager_init },
1715 { "destroy", "()V",
1716 (void*) android_content_AssetManager_destroy },
1717 { "getGlobalAssetCount", "()I",
1718 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001719 { "getAssetAllocations", "()Ljava/lang/String;",
1720 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 { "getGlobalAssetManagerCount", "()I",
1722 (void*) android_content_AssetManager_getGlobalAssetCount },
1723};
1724
1725int register_android_content_AssetManager(JNIEnv* env)
1726{
1727 jclass typedValue = env->FindClass("android/util/TypedValue");
1728 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1729 gTypedValueOffsets.mType
1730 = env->GetFieldID(typedValue, "type", "I");
1731 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1732 gTypedValueOffsets.mData
1733 = env->GetFieldID(typedValue, "data", "I");
1734 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1735 gTypedValueOffsets.mString
1736 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1737 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1738 gTypedValueOffsets.mAssetCookie
1739 = env->GetFieldID(typedValue, "assetCookie", "I");
1740 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1741 gTypedValueOffsets.mResourceId
1742 = env->GetFieldID(typedValue, "resourceId", "I");
1743 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1744 gTypedValueOffsets.mChangingConfigurations
1745 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1746 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1747 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1748 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1749
1750 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1751 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1752 gAssetFileDescriptorOffsets.mFd
1753 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1754 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1755 gAssetFileDescriptorOffsets.mStartOffset
1756 = env->GetFieldID(assetFd, "mStartOffset", "J");
1757 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1758 gAssetFileDescriptorOffsets.mLength
1759 = env->GetFieldID(assetFd, "mLength", "J");
1760 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1761
1762 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1763 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1764 gAssetManagerOffsets.mObject
1765 = env->GetFieldID(assetManager, "mObject", "I");
1766 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1767
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001768 jclass stringClass = env->FindClass("java/lang/String");
1769 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1770 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771
1772 return AndroidRuntime::registerNativeMethods(env,
1773 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1774}
1775
1776}; // namespace android