blob: 32f6ecf7cda304db7ed8113c0c06ecc5d703ca00 [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 size_t N = dir->getFileCount();
297
298 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +0100299 g_stringClass, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 delete dir;
302 return NULL;
303 }
304
305 for (size_t i=0; i<N; i++) {
306 const String8& name = dir->getFileName(i);
307 jstring str = env->NewStringUTF(name.string());
308 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 delete dir;
310 return NULL;
311 }
312 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700313 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 }
315
316 delete dir;
317
318 return array;
319}
320
321static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
322 jint asset)
323{
324 Asset* a = (Asset*)asset;
325
326 //printf("Destroying Asset Stream: %p\n", a);
327
328 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700329 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 return;
331 }
332
333 delete a;
334}
335
336static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
337 jint asset)
338{
339 Asset* a = (Asset*)asset;
340
341 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700342 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 return -1;
344 }
345
346 uint8_t b;
347 ssize_t res = a->read(&b, 1);
348 return res == 1 ? b : -1;
349}
350
351static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
352 jint asset, jbyteArray bArray,
353 jint off, jint len)
354{
355 Asset* a = (Asset*)asset;
356
357 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700358 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 return -1;
360 }
361
362 if (len == 0) {
363 return 0;
364 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 jsize bLen = env->GetArrayLength(bArray);
367 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700368 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 return -1;
370 }
371
372 jbyte* b = env->GetByteArrayElements(bArray, NULL);
373 ssize_t res = a->read(b+off, len);
374 env->ReleaseByteArrayElements(bArray, b, 0);
375
376 if (res > 0) return res;
377
378 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700379 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381 return -1;
382}
383
384static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
385 jint asset,
386 jlong offset, jint whence)
387{
388 Asset* a = (Asset*)asset;
389
390 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700391 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 return -1;
393 }
394
395 return a->seek(
396 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
397}
398
399static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
400 jint asset)
401{
402 Asset* a = (Asset*)asset;
403
404 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700405 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 return -1;
407 }
408
409 return a->getLength();
410}
411
412static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
413 jint asset)
414{
415 Asset* a = (Asset*)asset;
416
417 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700418 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 return -1;
420 }
421
422 return a->getRemainingLength();
423}
424
425static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
426 jstring path)
427{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700428 ScopedUtfChars path8(env, path);
429 if (path8.c_str() == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800430 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432
433 AssetManager* am = assetManagerForJavaObject(env, clazz);
434 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800435 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 void* cookie;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700439 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440
441 return (res) ? (jint)cookie : 0;
442}
443
444static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
445{
446 AssetManager* am = assetManagerForJavaObject(env, clazz);
447 if (am == NULL) {
448 return JNI_TRUE;
449 }
450 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
451}
452
453static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
454 jstring locale)
455{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700456 ScopedUtfChars locale8(env, locale);
457 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 return;
459 }
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 AssetManager* am = assetManagerForJavaObject(env, clazz);
462 if (am == NULL) {
463 return;
464 }
465
Elliott Hughes69a017b2011-04-08 14:10:28 -0700466 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467}
468
469static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
470{
471 Vector<String8> locales;
472
473 AssetManager* am = assetManagerForJavaObject(env, clazz);
474 if (am == NULL) {
475 return NULL;
476 }
477
478 am->getLocales(&locales);
479
480 const int N = locales.size();
481
482 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
483 if (result == NULL) {
484 return NULL;
485 }
486
487 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700488 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700489 if (str == NULL) {
490 return NULL;
491 }
492 env->SetObjectArrayElement(result, i, str);
493 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
495
496 return result;
497}
498
499static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
500 jint mcc, jint mnc,
501 jstring locale, jint orientation,
502 jint touchscreen, jint density,
503 jint keyboard, jint keyboardHidden,
504 jint navigation,
505 jint screenWidth, jint screenHeight,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700506 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700507 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100508 jint screenLayout, jint uiMode,
509 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510{
511 AssetManager* am = assetManagerForJavaObject(env, clazz);
512 if (am == NULL) {
513 return;
514 }
515
516 ResTable_config config;
517 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 config.mcc = (uint16_t)mcc;
522 config.mnc = (uint16_t)mnc;
523 config.orientation = (uint8_t)orientation;
524 config.touchscreen = (uint8_t)touchscreen;
525 config.density = (uint16_t)density;
526 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700527 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 config.navigation = (uint8_t)navigation;
529 config.screenWidth = (uint16_t)screenWidth;
530 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700531 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700532 config.screenWidthDp = (uint16_t)screenWidthDp;
533 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700534 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100535 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 config.sdkVersion = (uint16_t)sdkVersion;
537 config.minorVersion = 0;
538 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
541}
542
543static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
544 jstring name,
545 jstring defType,
546 jstring defPackage)
547{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700548 ScopedStringChars name16(env, name);
549 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 return 0;
551 }
552
553 AssetManager* am = assetManagerForJavaObject(env, clazz);
554 if (am == NULL) {
555 return 0;
556 }
557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 const char16_t* defType16 = defType
559 ? env->GetStringChars(defType, NULL) : NULL;
560 jsize defTypeLen = defType
561 ? env->GetStringLength(defType) : 0;
562 const char16_t* defPackage16 = defPackage
563 ? env->GetStringChars(defPackage, NULL) : NULL;
564 jsize defPackageLen = defPackage
565 ? env->GetStringLength(defPackage) : 0;
566
567 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700568 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569
570 if (defPackage16) {
571 env->ReleaseStringChars(defPackage, defPackage16);
572 }
573 if (defType16) {
574 env->ReleaseStringChars(defType, defType16);
575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
577 return ident;
578}
579
580static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
581 jint resid)
582{
583 AssetManager* am = assetManagerForJavaObject(env, clazz);
584 if (am == NULL) {
585 return NULL;
586 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 ResTable::resource_name name;
589 if (!am->getResources().getResourceName(resid, &name)) {
590 return NULL;
591 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 String16 str;
594 if (name.package != NULL) {
595 str.setTo(name.package, name.packageLen);
596 }
597 if (name.type != NULL) {
598 if (str.size() > 0) {
599 char16_t div = ':';
600 str.append(&div, 1);
601 }
602 str.append(name.type, name.typeLen);
603 }
604 if (name.name != NULL) {
605 if (str.size() > 0) {
606 char16_t div = '/';
607 str.append(&div, 1);
608 }
609 str.append(name.name, name.nameLen);
610 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 return env->NewString((const jchar*)str.string(), str.size());
613}
614
615static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
616 jint resid)
617{
618 AssetManager* am = assetManagerForJavaObject(env, clazz);
619 if (am == NULL) {
620 return NULL;
621 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 ResTable::resource_name name;
624 if (!am->getResources().getResourceName(resid, &name)) {
625 return NULL;
626 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 if (name.package != NULL) {
629 return env->NewString((const jchar*)name.package, name.packageLen);
630 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 return NULL;
633}
634
635static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
636 jint resid)
637{
638 AssetManager* am = assetManagerForJavaObject(env, clazz);
639 if (am == NULL) {
640 return NULL;
641 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 ResTable::resource_name name;
644 if (!am->getResources().getResourceName(resid, &name)) {
645 return NULL;
646 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 if (name.type != NULL) {
649 return env->NewString((const jchar*)name.type, name.typeLen);
650 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 return NULL;
653}
654
655static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
656 jint resid)
657{
658 AssetManager* am = assetManagerForJavaObject(env, clazz);
659 if (am == NULL) {
660 return NULL;
661 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 ResTable::resource_name name;
664 if (!am->getResources().getResourceName(resid, &name)) {
665 return NULL;
666 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 if (name.name != NULL) {
669 return env->NewString((const jchar*)name.name, name.nameLen);
670 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 return NULL;
673}
674
675static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
676 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700677 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 jobject outValue,
679 jboolean resolve)
680{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800681 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800682 jniThrowNullPointerException(env, "outValue");
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800683 return NULL;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 AssetManager* am = assetManagerForJavaObject(env, clazz);
686 if (am == NULL) {
687 return 0;
688 }
689 const ResTable& res(am->getResources());
690
691 Res_value value;
692 ResTable_config config;
693 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700694 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800695#if THROW_ON_BAD_ID
696 if (block == BAD_INDEX) {
697 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
698 return 0;
699 }
700#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 uint32_t ref = ident;
702 if (resolve) {
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700703 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800704#if THROW_ON_BAD_ID
705 if (block == BAD_INDEX) {
706 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
707 return 0;
708 }
709#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 }
711 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
712}
713
714static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
715 jint ident, jint bagEntryId,
716 jobject outValue, jboolean resolve)
717{
718 AssetManager* am = assetManagerForJavaObject(env, clazz);
719 if (am == NULL) {
720 return 0;
721 }
722 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 // Now lock down the resource object and start pulling stuff from it.
725 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 ssize_t block = -1;
728 Res_value value;
729
730 const ResTable::bag_entry* entry = NULL;
731 uint32_t typeSpecFlags;
732 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
733
734 for (ssize_t i=0; i<entryCount; i++) {
735 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
736 block = entry->stringBlock;
737 value = entry->map.value;
738 }
739 entry++;
740 }
741
742 res.unlock();
743
744 if (block < 0) {
745 return block;
746 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 uint32_t ref = ident;
749 if (resolve) {
750 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800751#if THROW_ON_BAD_ID
752 if (block == BAD_INDEX) {
753 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
754 return 0;
755 }
756#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 }
758 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
759}
760
761static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
762{
763 AssetManager* am = assetManagerForJavaObject(env, clazz);
764 if (am == NULL) {
765 return 0;
766 }
767 return am->getResources().getTableCount();
768}
769
770static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
771 jint block)
772{
773 AssetManager* am = assetManagerForJavaObject(env, clazz);
774 if (am == NULL) {
775 return 0;
776 }
777 return (jint)am->getResources().getTableStringBlock(block);
778}
779
780static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
781 jint cookie)
782{
783 AssetManager* am = assetManagerForJavaObject(env, clazz);
784 if (am == NULL) {
785 return NULL;
786 }
787 String8 name(am->getAssetPath((void*)cookie));
788 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700789 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 return NULL;
791 }
792 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 return str;
794}
795
796static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
797{
798 AssetManager* am = assetManagerForJavaObject(env, clazz);
799 if (am == NULL) {
800 return 0;
801 }
802 return (jint)(new ResTable::Theme(am->getResources()));
803}
804
805static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
806 jint themeInt)
807{
808 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
809 delete theme;
810}
811
812static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
813 jint themeInt,
814 jint styleRes,
815 jboolean force)
816{
817 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
818 theme->applyStyle(styleRes, force ? true : false);
819}
820
821static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
822 jint destInt, jint srcInt)
823{
824 ResTable::Theme* dest = (ResTable::Theme*)destInt;
825 ResTable::Theme* src = (ResTable::Theme*)srcInt;
826 dest->setTo(*src);
827}
828
829static jint android_content_AssetManager_loadThemeAttributeValue(
830 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
831{
832 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
833 const ResTable& res(theme->getResTable());
834
835 Res_value value;
836 // XXX value could be different in different configs!
837 uint32_t typeSpecFlags = 0;
838 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
839 uint32_t ref = 0;
840 if (resolve) {
841 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800842#if THROW_ON_BAD_ID
843 if (block == BAD_INDEX) {
844 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
845 return 0;
846 }
847#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
849 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
850}
851
852static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
853 jint themeInt, jint pri,
854 jstring tag, jstring prefix)
855{
856 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
857 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 // XXX Need to use params.
860 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861}
862
863static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
864 jint themeToken,
865 jint defStyleAttr,
866 jint defStyleRes,
867 jint xmlParserToken,
868 jintArray attrs,
869 jintArray outValues,
870 jintArray outIndices)
871{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700872 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700873 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700874 return JNI_FALSE;
875 }
876 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700877 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700878 return JNI_FALSE;
879 }
880 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700881 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 return JNI_FALSE;
883 }
884
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800885 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
886 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
889 const ResTable& res = theme->getResTable();
890 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700891 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 Res_value value;
893
894 const jsize NI = env->GetArrayLength(attrs);
895 const jsize NV = env->GetArrayLength(outValues);
896 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700897 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 return JNI_FALSE;
899 }
900
901 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
902 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 return JNI_FALSE;
904 }
905
906 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
907 jint* dest = baseDest;
908 if (dest == NULL) {
909 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 return JNI_FALSE;
911 }
912
913 jint* indices = NULL;
914 int indicesIdx = 0;
915 if (outIndices != NULL) {
916 if (env->GetArrayLength(outIndices) > NI) {
917 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
918 }
919 }
920
921 // Load default style from attribute, if specified...
922 uint32_t defStyleBagTypeSetFlags = 0;
923 if (defStyleAttr != 0) {
924 Res_value value;
925 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
926 if (value.dataType == Res_value::TYPE_REFERENCE) {
927 defStyleRes = value.data;
928 }
929 }
930 }
931
932 // Retrieve the style class associated with the current XML tag.
933 int style = 0;
934 uint32_t styleBagTypeSetFlags = 0;
935 if (xmlParser != NULL) {
936 ssize_t idx = xmlParser->indexOfStyle();
937 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
938 if (value.dataType == value.TYPE_ATTRIBUTE) {
939 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
940 value.dataType = Res_value::TYPE_NULL;
941 }
942 }
943 if (value.dataType == value.TYPE_REFERENCE) {
944 style = value.data;
945 }
946 }
947 }
948
949 // Now lock down the resource object and start pulling stuff from it.
950 res.lock();
951
952 // Retrieve the default style bag, if requested.
953 const ResTable::bag_entry* defStyleEnt = NULL;
954 uint32_t defStyleTypeSetFlags = 0;
955 ssize_t bagOff = defStyleRes != 0
956 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
957 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
958 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
959 (bagOff >= 0 ? bagOff : 0);
960
961 // Retrieve the style class bag, if requested.
962 const ResTable::bag_entry* styleEnt = NULL;
963 uint32_t styleTypeSetFlags = 0;
964 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
965 styleTypeSetFlags |= styleBagTypeSetFlags;
966 const ResTable::bag_entry* endStyleEnt = styleEnt +
967 (bagOff >= 0 ? bagOff : 0);
968
969 // Retrieve the XML attributes, if requested.
970 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
971 jsize ix=0;
972 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
973
974 static const ssize_t kXmlBlock = 0x10000000;
975
976 // Now iterate through all of the attributes that the client has requested,
977 // filling in each with whatever data we can find.
978 ssize_t block = 0;
979 uint32_t typeSetFlags;
980 for (jsize ii=0; ii<NI; ii++) {
981 const uint32_t curIdent = (uint32_t)src[ii];
982
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800983 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 // Try to find a value for this attribute... we prioritize values
986 // coming from, first XML attributes, then XML style, then default
987 // style, and finally the theme.
988 value.dataType = Res_value::TYPE_NULL;
989 value.data = 0;
990 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700991 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992
993 // Skip through XML attributes until the end or the next possible match.
994 while (ix < NX && curIdent > curXmlAttr) {
995 ix++;
996 curXmlAttr = xmlParser->getAttributeNameResID(ix);
997 }
998 // Retrieve the current XML attribute if it matches, and step to next.
999 if (ix < NX && curIdent == curXmlAttr) {
1000 block = kXmlBlock;
1001 xmlParser->getAttributeValue(ix, &value);
1002 ix++;
1003 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001004 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1005 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
1007
1008 // Skip through the style values until the end or the next possible match.
1009 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1010 styleEnt++;
1011 }
1012 // Retrieve the current style attribute if it matches, and step to next.
1013 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1014 if (value.dataType == Res_value::TYPE_NULL) {
1015 block = styleEnt->stringBlock;
1016 typeSetFlags = styleTypeSetFlags;
1017 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001018 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1019 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
1021 styleEnt++;
1022 }
1023
1024 // Skip through the default style values until the end or the next possible match.
1025 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1026 defStyleEnt++;
1027 }
1028 // Retrieve the current default style attribute if it matches, and step to next.
1029 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1030 if (value.dataType == Res_value::TYPE_NULL) {
1031 block = defStyleEnt->stringBlock;
1032 typeSetFlags = defStyleTypeSetFlags;
1033 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001034 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1035 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037 defStyleEnt++;
1038 }
1039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 uint32_t resid = 0;
1041 if (value.dataType != Res_value::TYPE_NULL) {
1042 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001043 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1044 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001046 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1047 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 } else {
1049 // If we still don't have a value for this attribute, try to find
1050 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1052 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001053 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1054 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001055 newBlock = res.resolveReference(&value, block, &resid,
1056 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001057#if THROW_ON_BAD_ID
1058 if (newBlock == BAD_INDEX) {
1059 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1060 return JNI_FALSE;
1061 }
1062#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001064 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1065 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 }
1067 }
1068
1069 // Deal with the special @null value -- it turns back to TYPE_NULL.
1070 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001071 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001073 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
1075
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001076 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1077 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078
1079 // Write the final value back to Java.
1080 dest[STYLE_TYPE] = value.dataType;
1081 dest[STYLE_DATA] = value.data;
1082 dest[STYLE_ASSET_COOKIE] =
1083 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1084 dest[STYLE_RESOURCE_ID] = resid;
1085 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001086 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1089 indicesIdx++;
1090 indices[indicesIdx] = ii;
1091 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 dest += STYLE_NUM_ENTRIES;
1094 }
1095
1096 res.unlock();
1097
1098 if (indices != NULL) {
1099 indices[0] = indicesIdx;
1100 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1101 }
1102 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1103 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1104
1105 return JNI_TRUE;
1106}
1107
1108static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1109 jint xmlParserToken,
1110 jintArray attrs,
1111 jintArray outValues,
1112 jintArray outIndices)
1113{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001114 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001115 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001116 return JNI_FALSE;
1117 }
1118 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001119 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001120 return JNI_FALSE;
1121 }
1122 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001123 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 return JNI_FALSE;
1125 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 AssetManager* am = assetManagerForJavaObject(env, clazz);
1128 if (am == NULL) {
1129 return JNI_FALSE;
1130 }
1131 const ResTable& res(am->getResources());
1132 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001133 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 const jsize NI = env->GetArrayLength(attrs);
1137 const jsize NV = env->GetArrayLength(outValues);
1138 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001139 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 return JNI_FALSE;
1141 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1144 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 return JNI_FALSE;
1146 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1149 jint* dest = baseDest;
1150 if (dest == NULL) {
1151 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
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* indices = NULL;
1156 int indicesIdx = 0;
1157 if (outIndices != NULL) {
1158 if (env->GetArrayLength(outIndices) > NI) {
1159 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1160 }
1161 }
1162
1163 // Now lock down the resource object and start pulling stuff from it.
1164 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 // Retrieve the XML attributes, if requested.
1167 const jsize NX = xmlParser->getAttributeCount();
1168 jsize ix=0;
1169 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 // Now iterate through all of the attributes that the client has requested,
1174 // filling in each with whatever data we can find.
1175 ssize_t block = 0;
1176 uint32_t typeSetFlags;
1177 for (jsize ii=0; ii<NI; ii++) {
1178 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 // Try to find a value for this attribute...
1181 value.dataType = Res_value::TYPE_NULL;
1182 value.data = 0;
1183 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001184 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 // Skip through XML attributes until the end or the next possible match.
1187 while (ix < NX && curIdent > curXmlAttr) {
1188 ix++;
1189 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1190 }
1191 // Retrieve the current XML attribute if it matches, and step to next.
1192 if (ix < NX && curIdent == curXmlAttr) {
1193 block = kXmlBlock;
1194 xmlParser->getAttributeValue(ix, &value);
1195 ix++;
1196 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1197 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1200 uint32_t resid = 0;
1201 if (value.dataType != Res_value::TYPE_NULL) {
1202 // Take care of resolving the found resource to its final value.
1203 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001204 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1205 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001206#if THROW_ON_BAD_ID
1207 if (newBlock == BAD_INDEX) {
1208 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1209 return JNI_FALSE;
1210 }
1211#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 if (newBlock >= 0) block = newBlock;
1213 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 // Deal with the special @null value -- it turns back to TYPE_NULL.
1216 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1217 value.dataType = Res_value::TYPE_NULL;
1218 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 // Write the final value back to Java.
1223 dest[STYLE_TYPE] = value.dataType;
1224 dest[STYLE_DATA] = value.data;
1225 dest[STYLE_ASSET_COOKIE] =
1226 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1227 dest[STYLE_RESOURCE_ID] = resid;
1228 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001229 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1232 indicesIdx++;
1233 indices[indicesIdx] = ii;
1234 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 dest += STYLE_NUM_ENTRIES;
1237 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 if (indices != NULL) {
1242 indices[0] = indicesIdx;
1243 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1244 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1247 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 return JNI_TRUE;
1250}
1251
1252static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1253 jint id)
1254{
1255 AssetManager* am = assetManagerForJavaObject(env, clazz);
1256 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001257 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 }
1259 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 res.lock();
1262 const ResTable::bag_entry* defStyleEnt = NULL;
1263 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1264 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 return bagOff;
1267}
1268
1269static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1270 jint id,
1271 jintArray outValues)
1272{
1273 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001274 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 return JNI_FALSE;
1276 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 AssetManager* am = assetManagerForJavaObject(env, clazz);
1279 if (am == NULL) {
1280 return JNI_FALSE;
1281 }
1282 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001283 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 Res_value value;
1285 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1290 jint* dest = baseDest;
1291 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001292 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 return JNI_FALSE;
1294 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 // Now lock down the resource object and start pulling stuff from it.
1297 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 const ResTable::bag_entry* arrayEnt = NULL;
1300 uint32_t arrayTypeSetFlags = 0;
1301 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1302 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1303 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 int i = 0;
1306 uint32_t typeSetFlags;
1307 while (i < NV && arrayEnt < endArrayEnt) {
1308 block = arrayEnt->stringBlock;
1309 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001310 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 uint32_t resid = 0;
1314 if (value.dataType != Res_value::TYPE_NULL) {
1315 // Take care of resolving the found resource to its final value.
1316 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001317 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1318 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001319#if THROW_ON_BAD_ID
1320 if (newBlock == BAD_INDEX) {
1321 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1322 return JNI_FALSE;
1323 }
1324#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 if (newBlock >= 0) block = newBlock;
1326 }
1327
1328 // Deal with the special @null value -- it turns back to TYPE_NULL.
1329 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1330 value.dataType = Res_value::TYPE_NULL;
1331 }
1332
1333 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1334
1335 // Write the final value back to Java.
1336 dest[STYLE_TYPE] = value.dataType;
1337 dest[STYLE_DATA] = value.data;
1338 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1339 dest[STYLE_RESOURCE_ID] = resid;
1340 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001341 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 dest += STYLE_NUM_ENTRIES;
1343 i+= STYLE_NUM_ENTRIES;
1344 arrayEnt++;
1345 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 return i;
1354}
1355
1356static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1357 jint cookie,
1358 jstring fileName)
1359{
1360 AssetManager* am = assetManagerForJavaObject(env, clazz);
1361 if (am == NULL) {
1362 return 0;
1363 }
1364
Steve Block71f2cf12011-10-20 11:56:00 +01001365 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366
Elliott Hughes69a017b2011-04-08 14:10:28 -07001367 ScopedUtfChars fileName8(env, fileName);
1368 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 return 0;
1370 }
1371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -07001373 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1374 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375
1376 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001377 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 return 0;
1379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380
1381 ResXMLTree* block = new ResXMLTree();
1382 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1383 a->close();
1384 delete a;
1385
1386 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001387 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 return 0;
1389 }
1390
1391 return (jint)block;
1392}
1393
1394static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1395 jint arrayResId)
1396{
1397 AssetManager* am = assetManagerForJavaObject(env, clazz);
1398 if (am == NULL) {
1399 return NULL;
1400 }
1401 const ResTable& res(am->getResources());
1402
1403 const ResTable::bag_entry* startOfBag;
1404 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1405 if (N < 0) {
1406 return NULL;
1407 }
1408
1409 jintArray array = env->NewIntArray(N * 2);
1410 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 res.unlockBag(startOfBag);
1412 return NULL;
1413 }
1414
1415 Res_value value;
1416 const ResTable::bag_entry* bag = startOfBag;
1417 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1418 jint stringIndex = -1;
1419 jint stringBlock = 0;
1420 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 // Take care of resolving the found resource to its final value.
1423 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1424 if (value.dataType == Res_value::TYPE_STRING) {
1425 stringIndex = value.data;
1426 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001427
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001428#if THROW_ON_BAD_ID
1429 if (stringBlock == BAD_INDEX) {
1430 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1431 return array;
1432 }
1433#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 //todo: It might be faster to allocate a C array to contain
1436 // the blocknums and indices, put them in there and then
1437 // do just one SetIntArrayRegion()
1438 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1439 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1440 j = j + 2;
1441 }
1442 res.unlockBag(startOfBag);
1443 return array;
1444}
1445
1446static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1447 jint arrayResId)
1448{
1449 AssetManager* am = assetManagerForJavaObject(env, clazz);
1450 if (am == NULL) {
1451 return NULL;
1452 }
1453 const ResTable& res(am->getResources());
1454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 const ResTable::bag_entry* startOfBag;
1456 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1457 if (N < 0) {
1458 return NULL;
1459 }
1460
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001461 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001462 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 res.unlockBag(startOfBag);
1464 return NULL;
1465 }
1466
1467 Res_value value;
1468 const ResTable::bag_entry* bag = startOfBag;
1469 size_t strLen = 0;
1470 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1471 value = bag->map.value;
1472 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 // Take care of resolving the found resource to its final value.
1475 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001476#if THROW_ON_BAD_ID
1477 if (block == BAD_INDEX) {
1478 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1479 return array;
1480 }
1481#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001483 const ResStringPool* pool = res.getTableStringBlock(block);
1484 const char* str8 = pool->string8At(value.data, &strLen);
1485 if (str8 != NULL) {
1486 str = env->NewStringUTF(str8);
1487 } else {
1488 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1489 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001490 }
1491
1492 // If one of our NewString{UTF} calls failed due to memory, an
1493 // exception will be pending.
1494 if (env->ExceptionCheck()) {
1495 res.unlockBag(startOfBag);
1496 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 }
Kenny Root780d2a12010-02-22 22:36:26 -08001498
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001499 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001500
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001501 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1502 // If we have a large amount of strings in our array, we might
1503 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001504 env->DeleteLocalRef(str);
1505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 }
1507 res.unlockBag(startOfBag);
1508 return array;
1509}
1510
1511static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1512 jint arrayResId)
1513{
1514 AssetManager* am = assetManagerForJavaObject(env, clazz);
1515 if (am == NULL) {
1516 return NULL;
1517 }
1518 const ResTable& res(am->getResources());
1519
1520 const ResTable::bag_entry* startOfBag;
1521 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1522 if (N < 0) {
1523 return NULL;
1524 }
1525
1526 jintArray array = env->NewIntArray(N);
1527 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 res.unlockBag(startOfBag);
1529 return NULL;
1530 }
1531
1532 Res_value value;
1533 const ResTable::bag_entry* bag = startOfBag;
1534 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1535 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 // Take care of resolving the found resource to its final value.
1538 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001539#if THROW_ON_BAD_ID
1540 if (block == BAD_INDEX) {
1541 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1542 return array;
1543 }
1544#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 if (value.dataType >= Res_value::TYPE_FIRST_INT
1546 && value.dataType <= Res_value::TYPE_LAST_INT) {
1547 int intVal = value.data;
1548 env->SetIntArrayRegion(array, i, 1, &intVal);
1549 }
1550 }
1551 res.unlockBag(startOfBag);
1552 return array;
1553}
1554
1555static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1556{
1557 AssetManager* am = new AssetManager();
1558 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001559 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 return;
1561 }
1562
1563 am->addDefaultAssets();
1564
Steve Block71f2cf12011-10-20 11:56:00 +01001565 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1567}
1568
1569static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1570{
1571 AssetManager* am = (AssetManager*)
1572 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001573 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 if (am != NULL) {
1575 delete am;
1576 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1577 }
1578}
1579
1580static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1581{
1582 return Asset::getGlobalCount();
1583}
1584
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001585static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1586{
1587 String8 alloc = Asset::getAssetAllocations();
1588 if (alloc.length() <= 0) {
1589 return NULL;
1590 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001591
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001592 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001593 return str;
1594}
1595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1597{
1598 return AssetManager::getGlobalCount();
1599}
1600
1601// ----------------------------------------------------------------------------
1602
1603/*
1604 * JNI registration.
1605 */
1606static JNINativeMethod gAssetManagerMethods[] = {
1607 /* name, signature, funcPtr */
1608
1609 // Basic asset stuff.
1610 { "openAsset", "(Ljava/lang/String;I)I",
1611 (void*) android_content_AssetManager_openAsset },
1612 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1613 (void*) android_content_AssetManager_openAssetFd },
1614 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1615 (void*) android_content_AssetManager_openNonAssetNative },
1616 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1617 (void*) android_content_AssetManager_openNonAssetFdNative },
1618 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1619 (void*) android_content_AssetManager_list },
1620 { "destroyAsset", "(I)V",
1621 (void*) android_content_AssetManager_destroyAsset },
1622 { "readAssetChar", "(I)I",
1623 (void*) android_content_AssetManager_readAssetChar },
1624 { "readAsset", "(I[BII)I",
1625 (void*) android_content_AssetManager_readAsset },
1626 { "seekAsset", "(IJI)J",
1627 (void*) android_content_AssetManager_seekAsset },
1628 { "getAssetLength", "(I)J",
1629 (void*) android_content_AssetManager_getAssetLength },
1630 { "getAssetRemainingLength", "(I)J",
1631 (void*) android_content_AssetManager_getAssetRemainingLength },
Dianne Hackbornf7be4802013-04-12 14:52:58 -07001632 { "addAssetPathNative", "(Ljava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 (void*) android_content_AssetManager_addAssetPath },
1634 { "isUpToDate", "()Z",
1635 (void*) android_content_AssetManager_isUpToDate },
1636
1637 // Resources.
1638 { "setLocale", "(Ljava/lang/String;)V",
1639 (void*) android_content_AssetManager_setLocale },
1640 { "getLocales", "()[Ljava/lang/String;",
1641 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001642 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 (void*) android_content_AssetManager_setConfiguration },
1644 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1645 (void*) android_content_AssetManager_getResourceIdentifier },
1646 { "getResourceName","(I)Ljava/lang/String;",
1647 (void*) android_content_AssetManager_getResourceName },
1648 { "getResourcePackageName","(I)Ljava/lang/String;",
1649 (void*) android_content_AssetManager_getResourcePackageName },
1650 { "getResourceTypeName","(I)Ljava/lang/String;",
1651 (void*) android_content_AssetManager_getResourceTypeName },
1652 { "getResourceEntryName","(I)Ljava/lang/String;",
1653 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001654 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 (void*) android_content_AssetManager_loadResourceValue },
1656 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1657 (void*) android_content_AssetManager_loadResourceBagValue },
1658 { "getStringBlockCount","()I",
1659 (void*) android_content_AssetManager_getStringBlockCount },
1660 { "getNativeStringBlock","(I)I",
1661 (void*) android_content_AssetManager_getNativeStringBlock },
1662 { "getCookieName","(I)Ljava/lang/String;",
1663 (void*) android_content_AssetManager_getCookieName },
1664
1665 // Themes.
1666 { "newTheme", "()I",
1667 (void*) android_content_AssetManager_newTheme },
1668 { "deleteTheme", "(I)V",
1669 (void*) android_content_AssetManager_deleteTheme },
1670 { "applyThemeStyle", "(IIZ)V",
1671 (void*) android_content_AssetManager_applyThemeStyle },
1672 { "copyTheme", "(II)V",
1673 (void*) android_content_AssetManager_copyTheme },
1674 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1675 (void*) android_content_AssetManager_loadThemeAttributeValue },
1676 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1677 (void*) android_content_AssetManager_dumpTheme },
1678 { "applyStyle","(IIII[I[I[I)Z",
1679 (void*) android_content_AssetManager_applyStyle },
1680 { "retrieveAttributes","(I[I[I[I)Z",
1681 (void*) android_content_AssetManager_retrieveAttributes },
1682 { "getArraySize","(I)I",
1683 (void*) android_content_AssetManager_getArraySize },
1684 { "retrieveArray","(I[I)I",
1685 (void*) android_content_AssetManager_retrieveArray },
1686
1687 // XML files.
1688 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1689 (void*) android_content_AssetManager_openXmlAssetNative },
1690
1691 // Arrays.
1692 { "getArrayStringResource","(I)[Ljava/lang/String;",
1693 (void*) android_content_AssetManager_getArrayStringResource },
1694 { "getArrayStringInfo","(I)[I",
1695 (void*) android_content_AssetManager_getArrayStringInfo },
1696 { "getArrayIntResource","(I)[I",
1697 (void*) android_content_AssetManager_getArrayIntResource },
1698
1699 // Bookkeeping.
1700 { "init", "()V",
1701 (void*) android_content_AssetManager_init },
1702 { "destroy", "()V",
1703 (void*) android_content_AssetManager_destroy },
1704 { "getGlobalAssetCount", "()I",
1705 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001706 { "getAssetAllocations", "()Ljava/lang/String;",
1707 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 { "getGlobalAssetManagerCount", "()I",
1709 (void*) android_content_AssetManager_getGlobalAssetCount },
1710};
1711
1712int register_android_content_AssetManager(JNIEnv* env)
1713{
1714 jclass typedValue = env->FindClass("android/util/TypedValue");
1715 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1716 gTypedValueOffsets.mType
1717 = env->GetFieldID(typedValue, "type", "I");
1718 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1719 gTypedValueOffsets.mData
1720 = env->GetFieldID(typedValue, "data", "I");
1721 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1722 gTypedValueOffsets.mString
1723 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1724 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1725 gTypedValueOffsets.mAssetCookie
1726 = env->GetFieldID(typedValue, "assetCookie", "I");
1727 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1728 gTypedValueOffsets.mResourceId
1729 = env->GetFieldID(typedValue, "resourceId", "I");
1730 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1731 gTypedValueOffsets.mChangingConfigurations
1732 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1733 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1734 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1735 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1736
1737 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1738 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1739 gAssetFileDescriptorOffsets.mFd
1740 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1741 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1742 gAssetFileDescriptorOffsets.mStartOffset
1743 = env->GetFieldID(assetFd, "mStartOffset", "J");
1744 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1745 gAssetFileDescriptorOffsets.mLength
1746 = env->GetFieldID(assetFd, "mLength", "J");
1747 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1748
1749 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1750 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1751 gAssetManagerOffsets.mObject
1752 = env->GetFieldID(assetManager, "mObject", "I");
1753 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1754
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001755 jclass stringClass = env->FindClass("java/lang/String");
1756 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1757 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001758 LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759
1760 return AndroidRuntime::registerNativeMethods(env,
1761 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1762}
1763
1764}; // namespace android