blob: 2c23f9db9468bd7fe871940530bb43b828db15a8 [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;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700589 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 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 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700597 if (name.type8 != NULL || name.type != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 if (str.size() > 0) {
599 char16_t div = ':';
600 str.append(&div, 1);
601 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700602 if (name.type8 != NULL) {
603 str.append(String16(name.type8, name.typeLen));
604 } else {
605 str.append(name.type, name.typeLen);
606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700608 if (name.name8 != NULL || name.name != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 if (str.size() > 0) {
610 char16_t div = '/';
611 str.append(&div, 1);
612 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700613 if (name.name8 != NULL) {
614 str.append(String16(name.name8, name.nameLen));
615 } else {
616 str.append(name.name, name.nameLen);
617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 return env->NewString((const jchar*)str.string(), str.size());
621}
622
623static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
624 jint resid)
625{
626 AssetManager* am = assetManagerForJavaObject(env, clazz);
627 if (am == NULL) {
628 return NULL;
629 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700632 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 return NULL;
634 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 if (name.package != NULL) {
637 return env->NewString((const jchar*)name.package, name.packageLen);
638 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 return NULL;
641}
642
643static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
644 jint resid)
645{
646 AssetManager* am = assetManagerForJavaObject(env, clazz);
647 if (am == NULL) {
648 return NULL;
649 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700652 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 return NULL;
654 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700655
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700656 if (name.type8 != NULL) {
657 return env->NewStringUTF(name.type8);
658 }
659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 if (name.type != NULL) {
661 return env->NewString((const jchar*)name.type, name.typeLen);
662 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 return NULL;
665}
666
667static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
668 jint resid)
669{
670 AssetManager* am = assetManagerForJavaObject(env, clazz);
671 if (am == NULL) {
672 return NULL;
673 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700676 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 return NULL;
678 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700679
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700680 if (name.name8 != NULL) {
681 return env->NewStringUTF(name.name8);
682 }
683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 if (name.name != NULL) {
685 return env->NewString((const jchar*)name.name, name.nameLen);
686 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 return NULL;
689}
690
691static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
692 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700693 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 jobject outValue,
695 jboolean resolve)
696{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800697 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800698 jniThrowNullPointerException(env, "outValue");
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700699 return 0;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 AssetManager* am = assetManagerForJavaObject(env, clazz);
702 if (am == NULL) {
703 return 0;
704 }
705 const ResTable& res(am->getResources());
706
707 Res_value value;
708 ResTable_config config;
709 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700710 ssize_t block = res.getResource(ident, &value, false, density, &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 uint32_t ref = ident;
718 if (resolve) {
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700719 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800720#if THROW_ON_BAD_ID
721 if (block == BAD_INDEX) {
722 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
723 return 0;
724 }
725#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 }
727 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
728}
729
730static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
731 jint ident, jint bagEntryId,
732 jobject outValue, jboolean resolve)
733{
734 AssetManager* am = assetManagerForJavaObject(env, clazz);
735 if (am == NULL) {
736 return 0;
737 }
738 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 // Now lock down the resource object and start pulling stuff from it.
741 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 ssize_t block = -1;
744 Res_value value;
745
746 const ResTable::bag_entry* entry = NULL;
747 uint32_t typeSpecFlags;
748 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
749
750 for (ssize_t i=0; i<entryCount; i++) {
751 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
752 block = entry->stringBlock;
753 value = entry->map.value;
754 }
755 entry++;
756 }
757
758 res.unlock();
759
760 if (block < 0) {
761 return block;
762 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 uint32_t ref = ident;
765 if (resolve) {
766 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800767#if THROW_ON_BAD_ID
768 if (block == BAD_INDEX) {
769 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
770 return 0;
771 }
772#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
775}
776
777static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
778{
779 AssetManager* am = assetManagerForJavaObject(env, clazz);
780 if (am == NULL) {
781 return 0;
782 }
783 return am->getResources().getTableCount();
784}
785
786static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
787 jint block)
788{
789 AssetManager* am = assetManagerForJavaObject(env, clazz);
790 if (am == NULL) {
791 return 0;
792 }
793 return (jint)am->getResources().getTableStringBlock(block);
794}
795
796static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
797 jint cookie)
798{
799 AssetManager* am = assetManagerForJavaObject(env, clazz);
800 if (am == NULL) {
801 return NULL;
802 }
803 String8 name(am->getAssetPath((void*)cookie));
804 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700805 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 return NULL;
807 }
808 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 return str;
810}
811
812static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
813{
814 AssetManager* am = assetManagerForJavaObject(env, clazz);
815 if (am == NULL) {
816 return 0;
817 }
818 return (jint)(new ResTable::Theme(am->getResources()));
819}
820
821static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
822 jint themeInt)
823{
824 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
825 delete theme;
826}
827
828static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
829 jint themeInt,
830 jint styleRes,
831 jboolean force)
832{
833 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
834 theme->applyStyle(styleRes, force ? true : false);
835}
836
837static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
838 jint destInt, jint srcInt)
839{
840 ResTable::Theme* dest = (ResTable::Theme*)destInt;
841 ResTable::Theme* src = (ResTable::Theme*)srcInt;
842 dest->setTo(*src);
843}
844
845static jint android_content_AssetManager_loadThemeAttributeValue(
846 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
847{
848 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
849 const ResTable& res(theme->getResTable());
850
851 Res_value value;
852 // XXX value could be different in different configs!
853 uint32_t typeSpecFlags = 0;
854 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
855 uint32_t ref = 0;
856 if (resolve) {
857 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800858#if THROW_ON_BAD_ID
859 if (block == BAD_INDEX) {
860 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
861 return 0;
862 }
863#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 }
865 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
866}
867
868static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
869 jint themeInt, jint pri,
870 jstring tag, jstring prefix)
871{
872 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
873 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 // XXX Need to use params.
876 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877}
878
879static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
880 jint themeToken,
881 jint defStyleAttr,
882 jint defStyleRes,
883 jint xmlParserToken,
884 jintArray attrs,
885 jintArray outValues,
886 jintArray outIndices)
887{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700888 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700889 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700890 return JNI_FALSE;
891 }
892 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700893 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700894 return JNI_FALSE;
895 }
896 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700897 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 return JNI_FALSE;
899 }
900
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800901 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
902 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
905 const ResTable& res = theme->getResTable();
906 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700907 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 Res_value value;
909
910 const jsize NI = env->GetArrayLength(attrs);
911 const jsize NV = env->GetArrayLength(outValues);
912 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700913 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 return JNI_FALSE;
915 }
916
917 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
918 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 return JNI_FALSE;
920 }
921
922 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
923 jint* dest = baseDest;
924 if (dest == NULL) {
925 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 return JNI_FALSE;
927 }
928
929 jint* indices = NULL;
930 int indicesIdx = 0;
931 if (outIndices != NULL) {
932 if (env->GetArrayLength(outIndices) > NI) {
933 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
934 }
935 }
936
937 // Load default style from attribute, if specified...
938 uint32_t defStyleBagTypeSetFlags = 0;
939 if (defStyleAttr != 0) {
940 Res_value value;
941 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
942 if (value.dataType == Res_value::TYPE_REFERENCE) {
943 defStyleRes = value.data;
944 }
945 }
946 }
947
948 // Retrieve the style class associated with the current XML tag.
949 int style = 0;
950 uint32_t styleBagTypeSetFlags = 0;
951 if (xmlParser != NULL) {
952 ssize_t idx = xmlParser->indexOfStyle();
953 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
954 if (value.dataType == value.TYPE_ATTRIBUTE) {
955 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
956 value.dataType = Res_value::TYPE_NULL;
957 }
958 }
959 if (value.dataType == value.TYPE_REFERENCE) {
960 style = value.data;
961 }
962 }
963 }
964
965 // Now lock down the resource object and start pulling stuff from it.
966 res.lock();
967
968 // Retrieve the default style bag, if requested.
969 const ResTable::bag_entry* defStyleEnt = NULL;
970 uint32_t defStyleTypeSetFlags = 0;
971 ssize_t bagOff = defStyleRes != 0
972 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
973 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
974 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
975 (bagOff >= 0 ? bagOff : 0);
976
977 // Retrieve the style class bag, if requested.
978 const ResTable::bag_entry* styleEnt = NULL;
979 uint32_t styleTypeSetFlags = 0;
980 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
981 styleTypeSetFlags |= styleBagTypeSetFlags;
982 const ResTable::bag_entry* endStyleEnt = styleEnt +
983 (bagOff >= 0 ? bagOff : 0);
984
985 // Retrieve the XML attributes, if requested.
986 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
987 jsize ix=0;
988 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
989
990 static const ssize_t kXmlBlock = 0x10000000;
991
992 // Now iterate through all of the attributes that the client has requested,
993 // filling in each with whatever data we can find.
994 ssize_t block = 0;
995 uint32_t typeSetFlags;
996 for (jsize ii=0; ii<NI; ii++) {
997 const uint32_t curIdent = (uint32_t)src[ii];
998
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800999 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -07001000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 // Try to find a value for this attribute... we prioritize values
1002 // coming from, first XML attributes, then XML style, then default
1003 // style, and finally the theme.
1004 value.dataType = Res_value::TYPE_NULL;
1005 value.data = 0;
1006 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001007 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008
1009 // Skip through XML attributes until the end or the next possible match.
1010 while (ix < NX && curIdent > curXmlAttr) {
1011 ix++;
1012 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1013 }
1014 // Retrieve the current XML attribute if it matches, and step to next.
1015 if (ix < NX && curIdent == curXmlAttr) {
1016 block = kXmlBlock;
1017 xmlParser->getAttributeValue(ix, &value);
1018 ix++;
1019 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001020 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1021 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 }
1023
1024 // Skip through the style values until the end or the next possible match.
1025 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1026 styleEnt++;
1027 }
1028 // Retrieve the current style attribute if it matches, and step to next.
1029 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1030 if (value.dataType == Res_value::TYPE_NULL) {
1031 block = styleEnt->stringBlock;
1032 typeSetFlags = styleTypeSetFlags;
1033 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001034 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1035 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037 styleEnt++;
1038 }
1039
1040 // Skip through the default style values until the end or the next possible match.
1041 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1042 defStyleEnt++;
1043 }
1044 // Retrieve the current default style attribute if it matches, and step to next.
1045 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1046 if (value.dataType == Res_value::TYPE_NULL) {
1047 block = defStyleEnt->stringBlock;
1048 typeSetFlags = defStyleTypeSetFlags;
1049 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001050 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1051 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 defStyleEnt++;
1054 }
1055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 uint32_t resid = 0;
1057 if (value.dataType != Res_value::TYPE_NULL) {
1058 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001059 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1060 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001062 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1063 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 } else {
1065 // If we still don't have a value for this attribute, try to find
1066 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1068 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001069 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1070 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001071 newBlock = res.resolveReference(&value, block, &resid,
1072 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001073#if THROW_ON_BAD_ID
1074 if (newBlock == BAD_INDEX) {
1075 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1076 return JNI_FALSE;
1077 }
1078#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001080 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1081 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083 }
1084
1085 // Deal with the special @null value -- it turns back to TYPE_NULL.
1086 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001087 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001089 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 }
1091
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001092 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1093 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094
1095 // Write the final value back to Java.
1096 dest[STYLE_TYPE] = value.dataType;
1097 dest[STYLE_DATA] = value.data;
1098 dest[STYLE_ASSET_COOKIE] =
1099 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1100 dest[STYLE_RESOURCE_ID] = resid;
1101 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001102 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1105 indicesIdx++;
1106 indices[indicesIdx] = ii;
1107 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 dest += STYLE_NUM_ENTRIES;
1110 }
1111
1112 res.unlock();
1113
1114 if (indices != NULL) {
1115 indices[0] = indicesIdx;
1116 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1117 }
1118 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1119 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1120
1121 return JNI_TRUE;
1122}
1123
1124static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1125 jint xmlParserToken,
1126 jintArray attrs,
1127 jintArray outValues,
1128 jintArray outIndices)
1129{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001130 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001131 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001132 return JNI_FALSE;
1133 }
1134 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001135 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001136 return JNI_FALSE;
1137 }
1138 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001139 jniThrowNullPointerException(env, "out values");
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 AssetManager* am = assetManagerForJavaObject(env, clazz);
1144 if (am == NULL) {
1145 return JNI_FALSE;
1146 }
1147 const ResTable& res(am->getResources());
1148 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001149 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 const jsize NI = env->GetArrayLength(attrs);
1153 const jsize NV = env->GetArrayLength(outValues);
1154 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001155 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 return JNI_FALSE;
1157 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1160 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 return JNI_FALSE;
1162 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1165 jint* dest = baseDest;
1166 if (dest == NULL) {
1167 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 return JNI_FALSE;
1169 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 jint* indices = NULL;
1172 int indicesIdx = 0;
1173 if (outIndices != NULL) {
1174 if (env->GetArrayLength(outIndices) > NI) {
1175 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1176 }
1177 }
1178
1179 // Now lock down the resource object and start pulling stuff from it.
1180 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 // Retrieve the XML attributes, if requested.
1183 const jsize NX = xmlParser->getAttributeCount();
1184 jsize ix=0;
1185 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 // Now iterate through all of the attributes that the client has requested,
1190 // filling in each with whatever data we can find.
1191 ssize_t block = 0;
1192 uint32_t typeSetFlags;
1193 for (jsize ii=0; ii<NI; ii++) {
1194 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 // Try to find a value for this attribute...
1197 value.dataType = Res_value::TYPE_NULL;
1198 value.data = 0;
1199 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001200 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 // Skip through XML attributes until the end or the next possible match.
1203 while (ix < NX && curIdent > curXmlAttr) {
1204 ix++;
1205 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1206 }
1207 // Retrieve the current XML attribute if it matches, and step to next.
1208 if (ix < NX && curIdent == curXmlAttr) {
1209 block = kXmlBlock;
1210 xmlParser->getAttributeValue(ix, &value);
1211 ix++;
1212 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1213 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1216 uint32_t resid = 0;
1217 if (value.dataType != Res_value::TYPE_NULL) {
1218 // Take care of resolving the found resource to its final value.
1219 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001220 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1221 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001222#if THROW_ON_BAD_ID
1223 if (newBlock == BAD_INDEX) {
1224 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1225 return JNI_FALSE;
1226 }
1227#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 if (newBlock >= 0) block = newBlock;
1229 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 // Deal with the special @null value -- it turns back to TYPE_NULL.
1232 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1233 value.dataType = Res_value::TYPE_NULL;
1234 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 // Write the final value back to Java.
1239 dest[STYLE_TYPE] = value.dataType;
1240 dest[STYLE_DATA] = value.data;
1241 dest[STYLE_ASSET_COOKIE] =
1242 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1243 dest[STYLE_RESOURCE_ID] = resid;
1244 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001245 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1248 indicesIdx++;
1249 indices[indicesIdx] = ii;
1250 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 dest += STYLE_NUM_ENTRIES;
1253 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 if (indices != NULL) {
1258 indices[0] = indicesIdx;
1259 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1260 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1263 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 return JNI_TRUE;
1266}
1267
1268static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1269 jint id)
1270{
1271 AssetManager* am = assetManagerForJavaObject(env, clazz);
1272 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001273 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 res.lock();
1278 const ResTable::bag_entry* defStyleEnt = NULL;
1279 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1280 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 return bagOff;
1283}
1284
1285static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1286 jint id,
1287 jintArray outValues)
1288{
1289 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001290 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 return JNI_FALSE;
1292 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 AssetManager* am = assetManagerForJavaObject(env, clazz);
1295 if (am == NULL) {
1296 return JNI_FALSE;
1297 }
1298 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001299 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 Res_value value;
1301 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1306 jint* dest = baseDest;
1307 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001308 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 return JNI_FALSE;
1310 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 // Now lock down the resource object and start pulling stuff from it.
1313 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 const ResTable::bag_entry* arrayEnt = NULL;
1316 uint32_t arrayTypeSetFlags = 0;
1317 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1318 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1319 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 int i = 0;
1322 uint32_t typeSetFlags;
1323 while (i < NV && arrayEnt < endArrayEnt) {
1324 block = arrayEnt->stringBlock;
1325 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001326 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 uint32_t resid = 0;
1330 if (value.dataType != Res_value::TYPE_NULL) {
1331 // Take care of resolving the found resource to its final value.
1332 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001333 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1334 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001335#if THROW_ON_BAD_ID
1336 if (newBlock == BAD_INDEX) {
1337 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1338 return JNI_FALSE;
1339 }
1340#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 if (newBlock >= 0) block = newBlock;
1342 }
1343
1344 // Deal with the special @null value -- it turns back to TYPE_NULL.
1345 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1346 value.dataType = Res_value::TYPE_NULL;
1347 }
1348
1349 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1350
1351 // Write the final value back to Java.
1352 dest[STYLE_TYPE] = value.dataType;
1353 dest[STYLE_DATA] = value.data;
1354 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1355 dest[STYLE_RESOURCE_ID] = resid;
1356 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001357 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 dest += STYLE_NUM_ENTRIES;
1359 i+= STYLE_NUM_ENTRIES;
1360 arrayEnt++;
1361 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 return i;
1370}
1371
1372static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1373 jint cookie,
1374 jstring fileName)
1375{
1376 AssetManager* am = assetManagerForJavaObject(env, clazz);
1377 if (am == NULL) {
1378 return 0;
1379 }
1380
Steve Block71f2cf12011-10-20 11:56:00 +01001381 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382
Elliott Hughes69a017b2011-04-08 14:10:28 -07001383 ScopedUtfChars fileName8(env, fileName);
1384 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 return 0;
1386 }
1387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -07001389 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1390 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391
1392 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001393 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 return 0;
1395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396
1397 ResXMLTree* block = new ResXMLTree();
1398 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1399 a->close();
1400 delete a;
1401
1402 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001403 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 return 0;
1405 }
1406
1407 return (jint)block;
1408}
1409
1410static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1411 jint arrayResId)
1412{
1413 AssetManager* am = assetManagerForJavaObject(env, clazz);
1414 if (am == NULL) {
1415 return NULL;
1416 }
1417 const ResTable& res(am->getResources());
1418
1419 const ResTable::bag_entry* startOfBag;
1420 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1421 if (N < 0) {
1422 return NULL;
1423 }
1424
1425 jintArray array = env->NewIntArray(N * 2);
1426 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 res.unlockBag(startOfBag);
1428 return NULL;
1429 }
1430
1431 Res_value value;
1432 const ResTable::bag_entry* bag = startOfBag;
1433 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1434 jint stringIndex = -1;
1435 jint stringBlock = 0;
1436 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 // Take care of resolving the found resource to its final value.
1439 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1440 if (value.dataType == Res_value::TYPE_STRING) {
1441 stringIndex = value.data;
1442 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001443
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001444#if THROW_ON_BAD_ID
1445 if (stringBlock == BAD_INDEX) {
1446 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1447 return array;
1448 }
1449#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 //todo: It might be faster to allocate a C array to contain
1452 // the blocknums and indices, put them in there and then
1453 // do just one SetIntArrayRegion()
1454 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1455 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1456 j = j + 2;
1457 }
1458 res.unlockBag(startOfBag);
1459 return array;
1460}
1461
1462static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1463 jint arrayResId)
1464{
1465 AssetManager* am = assetManagerForJavaObject(env, clazz);
1466 if (am == NULL) {
1467 return NULL;
1468 }
1469 const ResTable& res(am->getResources());
1470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 const ResTable::bag_entry* startOfBag;
1472 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1473 if (N < 0) {
1474 return NULL;
1475 }
1476
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001477 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001478 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 res.unlockBag(startOfBag);
1480 return NULL;
1481 }
1482
1483 Res_value value;
1484 const ResTable::bag_entry* bag = startOfBag;
1485 size_t strLen = 0;
1486 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1487 value = bag->map.value;
1488 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 // Take care of resolving the found resource to its final value.
1491 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001492#if THROW_ON_BAD_ID
1493 if (block == BAD_INDEX) {
1494 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1495 return array;
1496 }
1497#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001499 const ResStringPool* pool = res.getTableStringBlock(block);
1500 const char* str8 = pool->string8At(value.data, &strLen);
1501 if (str8 != NULL) {
1502 str = env->NewStringUTF(str8);
1503 } else {
1504 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1505 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001506 }
1507
1508 // If one of our NewString{UTF} calls failed due to memory, an
1509 // exception will be pending.
1510 if (env->ExceptionCheck()) {
1511 res.unlockBag(startOfBag);
1512 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
Kenny Root780d2a12010-02-22 22:36:26 -08001514
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001515 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001516
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001517 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1518 // If we have a large amount of strings in our array, we might
1519 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001520 env->DeleteLocalRef(str);
1521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 }
1523 res.unlockBag(startOfBag);
1524 return array;
1525}
1526
1527static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1528 jint arrayResId)
1529{
1530 AssetManager* am = assetManagerForJavaObject(env, clazz);
1531 if (am == NULL) {
1532 return NULL;
1533 }
1534 const ResTable& res(am->getResources());
1535
1536 const ResTable::bag_entry* startOfBag;
1537 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1538 if (N < 0) {
1539 return NULL;
1540 }
1541
1542 jintArray array = env->NewIntArray(N);
1543 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 res.unlockBag(startOfBag);
1545 return NULL;
1546 }
1547
1548 Res_value value;
1549 const ResTable::bag_entry* bag = startOfBag;
1550 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1551 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 // Take care of resolving the found resource to its final value.
1554 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001555#if THROW_ON_BAD_ID
1556 if (block == BAD_INDEX) {
1557 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1558 return array;
1559 }
1560#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 if (value.dataType >= Res_value::TYPE_FIRST_INT
1562 && value.dataType <= Res_value::TYPE_LAST_INT) {
1563 int intVal = value.data;
1564 env->SetIntArrayRegion(array, i, 1, &intVal);
1565 }
1566 }
1567 res.unlockBag(startOfBag);
1568 return array;
1569}
1570
1571static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1572{
1573 AssetManager* am = new AssetManager();
1574 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001575 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 return;
1577 }
1578
1579 am->addDefaultAssets();
1580
Steve Block71f2cf12011-10-20 11:56:00 +01001581 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1583}
1584
1585static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1586{
1587 AssetManager* am = (AssetManager*)
1588 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001589 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 if (am != NULL) {
1591 delete am;
1592 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1593 }
1594}
1595
1596static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1597{
1598 return Asset::getGlobalCount();
1599}
1600
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001601static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1602{
1603 String8 alloc = Asset::getAssetAllocations();
1604 if (alloc.length() <= 0) {
1605 return NULL;
1606 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001607
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001608 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001609 return str;
1610}
1611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1613{
1614 return AssetManager::getGlobalCount();
1615}
1616
1617// ----------------------------------------------------------------------------
1618
1619/*
1620 * JNI registration.
1621 */
1622static JNINativeMethod gAssetManagerMethods[] = {
1623 /* name, signature, funcPtr */
1624
1625 // Basic asset stuff.
1626 { "openAsset", "(Ljava/lang/String;I)I",
1627 (void*) android_content_AssetManager_openAsset },
1628 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1629 (void*) android_content_AssetManager_openAssetFd },
1630 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1631 (void*) android_content_AssetManager_openNonAssetNative },
1632 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1633 (void*) android_content_AssetManager_openNonAssetFdNative },
1634 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1635 (void*) android_content_AssetManager_list },
1636 { "destroyAsset", "(I)V",
1637 (void*) android_content_AssetManager_destroyAsset },
1638 { "readAssetChar", "(I)I",
1639 (void*) android_content_AssetManager_readAssetChar },
1640 { "readAsset", "(I[BII)I",
1641 (void*) android_content_AssetManager_readAsset },
1642 { "seekAsset", "(IJI)J",
1643 (void*) android_content_AssetManager_seekAsset },
1644 { "getAssetLength", "(I)J",
1645 (void*) android_content_AssetManager_getAssetLength },
1646 { "getAssetRemainingLength", "(I)J",
1647 (void*) android_content_AssetManager_getAssetRemainingLength },
Dianne Hackbornf7be4802013-04-12 14:52:58 -07001648 { "addAssetPathNative", "(Ljava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 (void*) android_content_AssetManager_addAssetPath },
1650 { "isUpToDate", "()Z",
1651 (void*) android_content_AssetManager_isUpToDate },
1652
1653 // Resources.
1654 { "setLocale", "(Ljava/lang/String;)V",
1655 (void*) android_content_AssetManager_setLocale },
1656 { "getLocales", "()[Ljava/lang/String;",
1657 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001658 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 (void*) android_content_AssetManager_setConfiguration },
1660 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1661 (void*) android_content_AssetManager_getResourceIdentifier },
1662 { "getResourceName","(I)Ljava/lang/String;",
1663 (void*) android_content_AssetManager_getResourceName },
1664 { "getResourcePackageName","(I)Ljava/lang/String;",
1665 (void*) android_content_AssetManager_getResourcePackageName },
1666 { "getResourceTypeName","(I)Ljava/lang/String;",
1667 (void*) android_content_AssetManager_getResourceTypeName },
1668 { "getResourceEntryName","(I)Ljava/lang/String;",
1669 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001670 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 (void*) android_content_AssetManager_loadResourceValue },
1672 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1673 (void*) android_content_AssetManager_loadResourceBagValue },
1674 { "getStringBlockCount","()I",
1675 (void*) android_content_AssetManager_getStringBlockCount },
1676 { "getNativeStringBlock","(I)I",
1677 (void*) android_content_AssetManager_getNativeStringBlock },
1678 { "getCookieName","(I)Ljava/lang/String;",
1679 (void*) android_content_AssetManager_getCookieName },
1680
1681 // Themes.
1682 { "newTheme", "()I",
1683 (void*) android_content_AssetManager_newTheme },
1684 { "deleteTheme", "(I)V",
1685 (void*) android_content_AssetManager_deleteTheme },
1686 { "applyThemeStyle", "(IIZ)V",
1687 (void*) android_content_AssetManager_applyThemeStyle },
1688 { "copyTheme", "(II)V",
1689 (void*) android_content_AssetManager_copyTheme },
1690 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1691 (void*) android_content_AssetManager_loadThemeAttributeValue },
1692 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1693 (void*) android_content_AssetManager_dumpTheme },
1694 { "applyStyle","(IIII[I[I[I)Z",
1695 (void*) android_content_AssetManager_applyStyle },
1696 { "retrieveAttributes","(I[I[I[I)Z",
1697 (void*) android_content_AssetManager_retrieveAttributes },
1698 { "getArraySize","(I)I",
1699 (void*) android_content_AssetManager_getArraySize },
1700 { "retrieveArray","(I[I)I",
1701 (void*) android_content_AssetManager_retrieveArray },
1702
1703 // XML files.
1704 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1705 (void*) android_content_AssetManager_openXmlAssetNative },
1706
1707 // Arrays.
1708 { "getArrayStringResource","(I)[Ljava/lang/String;",
1709 (void*) android_content_AssetManager_getArrayStringResource },
1710 { "getArrayStringInfo","(I)[I",
1711 (void*) android_content_AssetManager_getArrayStringInfo },
1712 { "getArrayIntResource","(I)[I",
1713 (void*) android_content_AssetManager_getArrayIntResource },
1714
1715 // Bookkeeping.
1716 { "init", "()V",
1717 (void*) android_content_AssetManager_init },
1718 { "destroy", "()V",
1719 (void*) android_content_AssetManager_destroy },
1720 { "getGlobalAssetCount", "()I",
1721 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001722 { "getAssetAllocations", "()Ljava/lang/String;",
1723 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 { "getGlobalAssetManagerCount", "()I",
1725 (void*) android_content_AssetManager_getGlobalAssetCount },
1726};
1727
1728int register_android_content_AssetManager(JNIEnv* env)
1729{
1730 jclass typedValue = env->FindClass("android/util/TypedValue");
1731 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1732 gTypedValueOffsets.mType
1733 = env->GetFieldID(typedValue, "type", "I");
1734 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1735 gTypedValueOffsets.mData
1736 = env->GetFieldID(typedValue, "data", "I");
1737 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1738 gTypedValueOffsets.mString
1739 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1740 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1741 gTypedValueOffsets.mAssetCookie
1742 = env->GetFieldID(typedValue, "assetCookie", "I");
1743 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1744 gTypedValueOffsets.mResourceId
1745 = env->GetFieldID(typedValue, "resourceId", "I");
1746 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1747 gTypedValueOffsets.mChangingConfigurations
1748 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1749 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1750 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1751 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1752
1753 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1754 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1755 gAssetFileDescriptorOffsets.mFd
1756 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1757 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1758 gAssetFileDescriptorOffsets.mStartOffset
1759 = env->GetFieldID(assetFd, "mStartOffset", "J");
1760 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1761 gAssetFileDescriptorOffsets.mLength
1762 = env->GetFieldID(assetFd, "mLength", "J");
1763 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1764
1765 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1766 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1767 gAssetManagerOffsets.mObject
1768 = env->GetFieldID(assetManager, "mObject", "I");
1769 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1770
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001771 jclass stringClass = env->FindClass("java/lang/String");
1772 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1773 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001774 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 -08001775
1776 return AndroidRuntime::registerNativeMethods(env,
1777 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1778}
1779
1780}; // namespace android