blob: 883691856bbe0ea0248aa616beb49b3a159e2bd2 [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
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000232 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
233 (Asset::AccessMode)mode)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700234 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
236 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700237 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 return -1;
239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 //printf("Created Asset Stream: %p\n", a);
242
243 return (jint)a;
244}
245
246static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
247 jint cookie,
248 jstring fileName,
249 jlongArray outOffsets)
250{
251 AssetManager* am = assetManagerForJavaObject(env, clazz);
252 if (am == NULL) {
253 return NULL;
254 }
255
Steve Block71f2cf12011-10-20 11:56:00 +0100256 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257
Elliott Hughes69a017b2011-04-08 14:10:28 -0700258 ScopedUtfChars fileName8(env, fileName);
259 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 return NULL;
261 }
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000264 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700265 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266
267 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700268 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 return NULL;
270 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271
272 //printf("Created Asset Stream: %p\n", a);
273
274 return returnParcelFileDescriptor(env, a, outOffsets);
275}
276
277static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
278 jstring fileName)
279{
280 AssetManager* am = assetManagerForJavaObject(env, clazz);
281 if (am == NULL) {
282 return NULL;
283 }
284
Elliott Hughes69a017b2011-04-08 14:10:28 -0700285 ScopedUtfChars fileName8(env, fileName);
286 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 return NULL;
288 }
289
Elliott Hughes69a017b2011-04-08 14:10:28 -0700290 AssetDir* dir = am->openDir(fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
292 if (dir == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700293 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 return NULL;
295 }
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 size_t N = dir->getFileCount();
298
299 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +0100300 g_stringClass, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 delete dir;
303 return NULL;
304 }
305
306 for (size_t i=0; i<N; i++) {
307 const String8& name = dir->getFileName(i);
308 jstring str = env->NewStringUTF(name.string());
309 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 delete dir;
311 return NULL;
312 }
313 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700314 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 delete dir;
318
319 return array;
320}
321
322static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
323 jint asset)
324{
325 Asset* a = (Asset*)asset;
326
327 //printf("Destroying Asset Stream: %p\n", a);
328
329 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700330 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 return;
332 }
333
334 delete a;
335}
336
337static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
338 jint asset)
339{
340 Asset* a = (Asset*)asset;
341
342 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700343 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 return -1;
345 }
346
347 uint8_t b;
348 ssize_t res = a->read(&b, 1);
349 return res == 1 ? b : -1;
350}
351
352static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
353 jint asset, jbyteArray bArray,
354 jint off, jint len)
355{
356 Asset* a = (Asset*)asset;
357
358 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700359 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 return -1;
361 }
362
363 if (len == 0) {
364 return 0;
365 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 jsize bLen = env->GetArrayLength(bArray);
368 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700369 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 return -1;
371 }
372
373 jbyte* b = env->GetByteArrayElements(bArray, NULL);
374 ssize_t res = a->read(b+off, len);
375 env->ReleaseByteArrayElements(bArray, b, 0);
376
377 if (res > 0) return res;
378
379 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700380 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 }
382 return -1;
383}
384
385static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
386 jint asset,
387 jlong offset, jint whence)
388{
389 Asset* a = (Asset*)asset;
390
391 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700392 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 return -1;
394 }
395
396 return a->seek(
397 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
398}
399
400static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
401 jint asset)
402{
403 Asset* a = (Asset*)asset;
404
405 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700406 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 return -1;
408 }
409
410 return a->getLength();
411}
412
413static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
414 jint asset)
415{
416 Asset* a = (Asset*)asset;
417
418 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700419 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return -1;
421 }
422
423 return a->getRemainingLength();
424}
425
426static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
427 jstring path)
428{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700429 ScopedUtfChars path8(env, path);
430 if (path8.c_str() == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800431 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 }
433
434 AssetManager* am = assetManagerForJavaObject(env, clazz);
435 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800436 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 }
438
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000439 int32_t cookie;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700440 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000442 return (res) ? static_cast<jint>(cookie) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443}
444
445static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
446{
447 AssetManager* am = assetManagerForJavaObject(env, clazz);
448 if (am == NULL) {
449 return JNI_TRUE;
450 }
451 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
452}
453
454static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
455 jstring locale)
456{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700457 ScopedUtfChars locale8(env, locale);
458 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 return;
460 }
461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 AssetManager* am = assetManagerForJavaObject(env, clazz);
463 if (am == NULL) {
464 return;
465 }
466
Elliott Hughes69a017b2011-04-08 14:10:28 -0700467 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468}
469
470static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
471{
472 Vector<String8> locales;
473
474 AssetManager* am = assetManagerForJavaObject(env, clazz);
475 if (am == NULL) {
476 return NULL;
477 }
478
479 am->getLocales(&locales);
480
481 const int N = locales.size();
482
483 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
484 if (result == NULL) {
485 return NULL;
486 }
487
488 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700489 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700490 if (str == NULL) {
491 return NULL;
492 }
493 env->SetObjectArrayElement(result, i, str);
494 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
496
497 return result;
498}
499
500static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
501 jint mcc, jint mnc,
502 jstring locale, jint orientation,
503 jint touchscreen, jint density,
504 jint keyboard, jint keyboardHidden,
505 jint navigation,
506 jint screenWidth, jint screenHeight,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700507 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700508 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100509 jint screenLayout, jint uiMode,
510 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511{
512 AssetManager* am = assetManagerForJavaObject(env, clazz);
513 if (am == NULL) {
514 return;
515 }
516
517 ResTable_config config;
518 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 config.mcc = (uint16_t)mcc;
523 config.mnc = (uint16_t)mnc;
524 config.orientation = (uint8_t)orientation;
525 config.touchscreen = (uint8_t)touchscreen;
526 config.density = (uint16_t)density;
527 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700528 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 config.navigation = (uint8_t)navigation;
530 config.screenWidth = (uint16_t)screenWidth;
531 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700532 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700533 config.screenWidthDp = (uint16_t)screenWidthDp;
534 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700535 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100536 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 config.sdkVersion = (uint16_t)sdkVersion;
538 config.minorVersion = 0;
539 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
542}
543
544static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
545 jstring name,
546 jstring defType,
547 jstring defPackage)
548{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700549 ScopedStringChars name16(env, name);
550 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 return 0;
552 }
553
554 AssetManager* am = assetManagerForJavaObject(env, clazz);
555 if (am == NULL) {
556 return 0;
557 }
558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 const char16_t* defType16 = defType
560 ? env->GetStringChars(defType, NULL) : NULL;
561 jsize defTypeLen = defType
562 ? env->GetStringLength(defType) : 0;
563 const char16_t* defPackage16 = defPackage
564 ? env->GetStringChars(defPackage, NULL) : NULL;
565 jsize defPackageLen = defPackage
566 ? env->GetStringLength(defPackage) : 0;
567
568 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700569 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570
571 if (defPackage16) {
572 env->ReleaseStringChars(defPackage, defPackage16);
573 }
574 if (defType16) {
575 env->ReleaseStringChars(defType, defType16);
576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577
578 return ident;
579}
580
581static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
582 jint resid)
583{
584 AssetManager* am = assetManagerForJavaObject(env, clazz);
585 if (am == NULL) {
586 return NULL;
587 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700590 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 return NULL;
592 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 String16 str;
595 if (name.package != NULL) {
596 str.setTo(name.package, name.packageLen);
597 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700598 if (name.type8 != NULL || name.type != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 if (str.size() > 0) {
600 char16_t div = ':';
601 str.append(&div, 1);
602 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700603 if (name.type8 != NULL) {
604 str.append(String16(name.type8, name.typeLen));
605 } else {
606 str.append(name.type, name.typeLen);
607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700609 if (name.name8 != NULL || name.name != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 if (str.size() > 0) {
611 char16_t div = '/';
612 str.append(&div, 1);
613 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700614 if (name.name8 != NULL) {
615 str.append(String16(name.name8, name.nameLen));
616 } else {
617 str.append(name.name, name.nameLen);
618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 return env->NewString((const jchar*)str.string(), str.size());
622}
623
624static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
625 jint resid)
626{
627 AssetManager* am = assetManagerForJavaObject(env, clazz);
628 if (am == NULL) {
629 return NULL;
630 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700633 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 return NULL;
635 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 if (name.package != NULL) {
638 return env->NewString((const jchar*)name.package, name.packageLen);
639 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 return NULL;
642}
643
644static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
645 jint resid)
646{
647 AssetManager* am = assetManagerForJavaObject(env, clazz);
648 if (am == NULL) {
649 return NULL;
650 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700653 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 return NULL;
655 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700656
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700657 if (name.type8 != NULL) {
658 return env->NewStringUTF(name.type8);
659 }
660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 if (name.type != NULL) {
662 return env->NewString((const jchar*)name.type, name.typeLen);
663 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 return NULL;
666}
667
668static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
669 jint resid)
670{
671 AssetManager* am = assetManagerForJavaObject(env, clazz);
672 if (am == NULL) {
673 return NULL;
674 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700677 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 return NULL;
679 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700680
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700681 if (name.name8 != NULL) {
682 return env->NewStringUTF(name.name8);
683 }
684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 if (name.name != NULL) {
686 return env->NewString((const jchar*)name.name, name.nameLen);
687 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 return NULL;
690}
691
692static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
693 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700694 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 jobject outValue,
696 jboolean resolve)
697{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800698 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800699 jniThrowNullPointerException(env, "outValue");
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700700 return 0;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 AssetManager* am = assetManagerForJavaObject(env, clazz);
703 if (am == NULL) {
704 return 0;
705 }
706 const ResTable& res(am->getResources());
707
708 Res_value value;
709 ResTable_config config;
710 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700711 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800712#if THROW_ON_BAD_ID
713 if (block == BAD_INDEX) {
714 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
715 return 0;
716 }
717#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 uint32_t ref = ident;
719 if (resolve) {
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700720 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800721#if THROW_ON_BAD_ID
722 if (block == BAD_INDEX) {
723 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
724 return 0;
725 }
726#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 }
728 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
729}
730
731static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
732 jint ident, jint bagEntryId,
733 jobject outValue, jboolean resolve)
734{
735 AssetManager* am = assetManagerForJavaObject(env, clazz);
736 if (am == NULL) {
737 return 0;
738 }
739 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 // Now lock down the resource object and start pulling stuff from it.
742 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 ssize_t block = -1;
745 Res_value value;
746
747 const ResTable::bag_entry* entry = NULL;
748 uint32_t typeSpecFlags;
749 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
750
751 for (ssize_t i=0; i<entryCount; i++) {
752 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
753 block = entry->stringBlock;
754 value = entry->map.value;
755 }
756 entry++;
757 }
758
759 res.unlock();
760
761 if (block < 0) {
762 return block;
763 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 uint32_t ref = ident;
766 if (resolve) {
767 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800768#if THROW_ON_BAD_ID
769 if (block == BAD_INDEX) {
770 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
771 return 0;
772 }
773#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 }
775 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
776}
777
778static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
779{
780 AssetManager* am = assetManagerForJavaObject(env, clazz);
781 if (am == NULL) {
782 return 0;
783 }
784 return am->getResources().getTableCount();
785}
786
787static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
788 jint block)
789{
790 AssetManager* am = assetManagerForJavaObject(env, clazz);
791 if (am == NULL) {
792 return 0;
793 }
794 return (jint)am->getResources().getTableStringBlock(block);
795}
796
797static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
798 jint cookie)
799{
800 AssetManager* am = assetManagerForJavaObject(env, clazz);
801 if (am == NULL) {
802 return NULL;
803 }
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000804 String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700806 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 return NULL;
808 }
809 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 return str;
811}
812
813static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
814{
815 AssetManager* am = assetManagerForJavaObject(env, clazz);
816 if (am == NULL) {
817 return 0;
818 }
819 return (jint)(new ResTable::Theme(am->getResources()));
820}
821
822static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
823 jint themeInt)
824{
825 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
826 delete theme;
827}
828
829static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
830 jint themeInt,
831 jint styleRes,
832 jboolean force)
833{
834 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
835 theme->applyStyle(styleRes, force ? true : false);
836}
837
838static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
839 jint destInt, jint srcInt)
840{
841 ResTable::Theme* dest = (ResTable::Theme*)destInt;
842 ResTable::Theme* src = (ResTable::Theme*)srcInt;
843 dest->setTo(*src);
844}
845
846static jint android_content_AssetManager_loadThemeAttributeValue(
847 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
848{
849 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
850 const ResTable& res(theme->getResTable());
851
852 Res_value value;
853 // XXX value could be different in different configs!
854 uint32_t typeSpecFlags = 0;
855 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
856 uint32_t ref = 0;
857 if (resolve) {
858 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800859#if THROW_ON_BAD_ID
860 if (block == BAD_INDEX) {
861 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
862 return 0;
863 }
864#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
866 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
867}
868
869static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
870 jint themeInt, jint pri,
871 jstring tag, jstring prefix)
872{
873 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
874 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 // XXX Need to use params.
877 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878}
879
880static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
881 jint themeToken,
882 jint defStyleAttr,
883 jint defStyleRes,
884 jint xmlParserToken,
885 jintArray attrs,
886 jintArray outValues,
887 jintArray outIndices)
888{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700889 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700890 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700891 return JNI_FALSE;
892 }
893 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700894 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700895 return JNI_FALSE;
896 }
897 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700898 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 return JNI_FALSE;
900 }
901
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800902 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
903 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
906 const ResTable& res = theme->getResTable();
907 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700908 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 Res_value value;
910
911 const jsize NI = env->GetArrayLength(attrs);
912 const jsize NV = env->GetArrayLength(outValues);
913 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700914 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 return JNI_FALSE;
916 }
917
918 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
919 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 return JNI_FALSE;
921 }
922
923 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
924 jint* dest = baseDest;
925 if (dest == NULL) {
926 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 return JNI_FALSE;
928 }
929
930 jint* indices = NULL;
931 int indicesIdx = 0;
932 if (outIndices != NULL) {
933 if (env->GetArrayLength(outIndices) > NI) {
934 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
935 }
936 }
937
938 // Load default style from attribute, if specified...
939 uint32_t defStyleBagTypeSetFlags = 0;
940 if (defStyleAttr != 0) {
941 Res_value value;
942 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
943 if (value.dataType == Res_value::TYPE_REFERENCE) {
944 defStyleRes = value.data;
945 }
946 }
947 }
948
949 // Retrieve the style class associated with the current XML tag.
950 int style = 0;
951 uint32_t styleBagTypeSetFlags = 0;
952 if (xmlParser != NULL) {
953 ssize_t idx = xmlParser->indexOfStyle();
954 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
955 if (value.dataType == value.TYPE_ATTRIBUTE) {
956 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
957 value.dataType = Res_value::TYPE_NULL;
958 }
959 }
960 if (value.dataType == value.TYPE_REFERENCE) {
961 style = value.data;
962 }
963 }
964 }
965
966 // Now lock down the resource object and start pulling stuff from it.
967 res.lock();
968
969 // Retrieve the default style bag, if requested.
970 const ResTable::bag_entry* defStyleEnt = NULL;
971 uint32_t defStyleTypeSetFlags = 0;
972 ssize_t bagOff = defStyleRes != 0
973 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
974 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
975 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
976 (bagOff >= 0 ? bagOff : 0);
977
978 // Retrieve the style class bag, if requested.
979 const ResTable::bag_entry* styleEnt = NULL;
980 uint32_t styleTypeSetFlags = 0;
981 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
982 styleTypeSetFlags |= styleBagTypeSetFlags;
983 const ResTable::bag_entry* endStyleEnt = styleEnt +
984 (bagOff >= 0 ? bagOff : 0);
985
986 // Retrieve the XML attributes, if requested.
987 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
988 jsize ix=0;
989 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
990
991 static const ssize_t kXmlBlock = 0x10000000;
992
993 // Now iterate through all of the attributes that the client has requested,
994 // filling in each with whatever data we can find.
995 ssize_t block = 0;
996 uint32_t typeSetFlags;
997 for (jsize ii=0; ii<NI; ii++) {
998 const uint32_t curIdent = (uint32_t)src[ii];
999
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001000 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -07001001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 // Try to find a value for this attribute... we prioritize values
1003 // coming from, first XML attributes, then XML style, then default
1004 // style, and finally the theme.
1005 value.dataType = Res_value::TYPE_NULL;
1006 value.data = 0;
1007 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001008 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009
1010 // Skip through XML attributes until the end or the next possible match.
1011 while (ix < NX && curIdent > curXmlAttr) {
1012 ix++;
1013 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1014 }
1015 // Retrieve the current XML attribute if it matches, and step to next.
1016 if (ix < NX && curIdent == curXmlAttr) {
1017 block = kXmlBlock;
1018 xmlParser->getAttributeValue(ix, &value);
1019 ix++;
1020 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001021 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1022 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024
1025 // Skip through the style values until the end or the next possible match.
1026 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1027 styleEnt++;
1028 }
1029 // Retrieve the current style attribute if it matches, and step to next.
1030 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1031 if (value.dataType == Res_value::TYPE_NULL) {
1032 block = styleEnt->stringBlock;
1033 typeSetFlags = styleTypeSetFlags;
1034 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001035 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1036 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 }
1038 styleEnt++;
1039 }
1040
1041 // Skip through the default style values until the end or the next possible match.
1042 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1043 defStyleEnt++;
1044 }
1045 // Retrieve the current default style attribute if it matches, and step to next.
1046 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1047 if (value.dataType == Res_value::TYPE_NULL) {
1048 block = defStyleEnt->stringBlock;
1049 typeSetFlags = defStyleTypeSetFlags;
1050 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001051 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1052 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054 defStyleEnt++;
1055 }
1056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 uint32_t resid = 0;
1058 if (value.dataType != Res_value::TYPE_NULL) {
1059 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001060 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1061 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001063 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1064 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 } else {
1066 // If we still don't have a value for this attribute, try to find
1067 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1069 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001070 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1071 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001072 newBlock = res.resolveReference(&value, block, &resid,
1073 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001074#if THROW_ON_BAD_ID
1075 if (newBlock == BAD_INDEX) {
1076 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1077 return JNI_FALSE;
1078 }
1079#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001081 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1082 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084 }
1085
1086 // Deal with the special @null value -- it turns back to TYPE_NULL.
1087 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001088 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001090 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001093 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1094 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095
1096 // Write the final value back to Java.
1097 dest[STYLE_TYPE] = value.dataType;
1098 dest[STYLE_DATA] = value.data;
1099 dest[STYLE_ASSET_COOKIE] =
1100 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1101 dest[STYLE_RESOURCE_ID] = resid;
1102 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001103 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1106 indicesIdx++;
1107 indices[indicesIdx] = ii;
1108 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 dest += STYLE_NUM_ENTRIES;
1111 }
1112
1113 res.unlock();
1114
1115 if (indices != NULL) {
1116 indices[0] = indicesIdx;
1117 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1118 }
1119 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1120 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1121
1122 return JNI_TRUE;
1123}
1124
1125static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1126 jint xmlParserToken,
1127 jintArray attrs,
1128 jintArray outValues,
1129 jintArray outIndices)
1130{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001131 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001132 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001133 return JNI_FALSE;
1134 }
1135 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001136 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001137 return JNI_FALSE;
1138 }
1139 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001140 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 return JNI_FALSE;
1142 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 AssetManager* am = assetManagerForJavaObject(env, clazz);
1145 if (am == NULL) {
1146 return JNI_FALSE;
1147 }
1148 const ResTable& res(am->getResources());
1149 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001150 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 const jsize NI = env->GetArrayLength(attrs);
1154 const jsize NV = env->GetArrayLength(outValues);
1155 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001156 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 return JNI_FALSE;
1158 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1161 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 return JNI_FALSE;
1163 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1166 jint* dest = baseDest;
1167 if (dest == NULL) {
1168 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 return JNI_FALSE;
1170 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 jint* indices = NULL;
1173 int indicesIdx = 0;
1174 if (outIndices != NULL) {
1175 if (env->GetArrayLength(outIndices) > NI) {
1176 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1177 }
1178 }
1179
1180 // Now lock down the resource object and start pulling stuff from it.
1181 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 // Retrieve the XML attributes, if requested.
1184 const jsize NX = xmlParser->getAttributeCount();
1185 jsize ix=0;
1186 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 // Now iterate through all of the attributes that the client has requested,
1191 // filling in each with whatever data we can find.
1192 ssize_t block = 0;
1193 uint32_t typeSetFlags;
1194 for (jsize ii=0; ii<NI; ii++) {
1195 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 // Try to find a value for this attribute...
1198 value.dataType = Res_value::TYPE_NULL;
1199 value.data = 0;
1200 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001201 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 // Skip through XML attributes until the end or the next possible match.
1204 while (ix < NX && curIdent > curXmlAttr) {
1205 ix++;
1206 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1207 }
1208 // Retrieve the current XML attribute if it matches, and step to next.
1209 if (ix < NX && curIdent == curXmlAttr) {
1210 block = kXmlBlock;
1211 xmlParser->getAttributeValue(ix, &value);
1212 ix++;
1213 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1214 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1217 uint32_t resid = 0;
1218 if (value.dataType != Res_value::TYPE_NULL) {
1219 // Take care of resolving the found resource to its final value.
1220 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001221 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1222 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001223#if THROW_ON_BAD_ID
1224 if (newBlock == BAD_INDEX) {
1225 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1226 return JNI_FALSE;
1227 }
1228#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 if (newBlock >= 0) block = newBlock;
1230 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 // Deal with the special @null value -- it turns back to TYPE_NULL.
1233 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1234 value.dataType = Res_value::TYPE_NULL;
1235 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 // Write the final value back to Java.
1240 dest[STYLE_TYPE] = value.dataType;
1241 dest[STYLE_DATA] = value.data;
1242 dest[STYLE_ASSET_COOKIE] =
1243 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1244 dest[STYLE_RESOURCE_ID] = resid;
1245 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001246 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1249 indicesIdx++;
1250 indices[indicesIdx] = ii;
1251 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 dest += STYLE_NUM_ENTRIES;
1254 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 if (indices != NULL) {
1259 indices[0] = indicesIdx;
1260 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1261 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1264 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 return JNI_TRUE;
1267}
1268
1269static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1270 jint id)
1271{
1272 AssetManager* am = assetManagerForJavaObject(env, clazz);
1273 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001274 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
1276 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 res.lock();
1279 const ResTable::bag_entry* defStyleEnt = NULL;
1280 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1281 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 return bagOff;
1284}
1285
1286static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1287 jint id,
1288 jintArray outValues)
1289{
1290 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001291 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 return JNI_FALSE;
1293 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 AssetManager* am = assetManagerForJavaObject(env, clazz);
1296 if (am == NULL) {
1297 return JNI_FALSE;
1298 }
1299 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001300 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 Res_value value;
1302 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1307 jint* dest = baseDest;
1308 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001309 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 return JNI_FALSE;
1311 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 // Now lock down the resource object and start pulling stuff from it.
1314 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 const ResTable::bag_entry* arrayEnt = NULL;
1317 uint32_t arrayTypeSetFlags = 0;
1318 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1319 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1320 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 int i = 0;
1323 uint32_t typeSetFlags;
1324 while (i < NV && arrayEnt < endArrayEnt) {
1325 block = arrayEnt->stringBlock;
1326 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001327 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 uint32_t resid = 0;
1331 if (value.dataType != Res_value::TYPE_NULL) {
1332 // Take care of resolving the found resource to its final value.
1333 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001334 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1335 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001336#if THROW_ON_BAD_ID
1337 if (newBlock == BAD_INDEX) {
1338 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1339 return JNI_FALSE;
1340 }
1341#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 if (newBlock >= 0) block = newBlock;
1343 }
1344
1345 // Deal with the special @null value -- it turns back to TYPE_NULL.
1346 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1347 value.dataType = Res_value::TYPE_NULL;
1348 }
1349
1350 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1351
1352 // Write the final value back to Java.
1353 dest[STYLE_TYPE] = value.dataType;
1354 dest[STYLE_DATA] = value.data;
1355 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1356 dest[STYLE_RESOURCE_ID] = resid;
1357 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001358 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 dest += STYLE_NUM_ENTRIES;
1360 i+= STYLE_NUM_ENTRIES;
1361 arrayEnt++;
1362 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 return i;
1371}
1372
1373static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1374 jint cookie,
1375 jstring fileName)
1376{
1377 AssetManager* am = assetManagerForJavaObject(env, clazz);
1378 if (am == NULL) {
1379 return 0;
1380 }
1381
Steve Block71f2cf12011-10-20 11:56:00 +01001382 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383
Elliott Hughes69a017b2011-04-08 14:10:28 -07001384 ScopedUtfChars fileName8(env, fileName);
1385 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 return 0;
1387 }
1388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +00001390 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_BUFFER)
Elliott Hughes69a017b2011-04-08 14:10:28 -07001391 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392
1393 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001394 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 return 0;
1396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397
1398 ResXMLTree* block = new ResXMLTree();
1399 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1400 a->close();
1401 delete a;
1402
1403 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001404 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 return 0;
1406 }
1407
1408 return (jint)block;
1409}
1410
1411static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1412 jint arrayResId)
1413{
1414 AssetManager* am = assetManagerForJavaObject(env, clazz);
1415 if (am == NULL) {
1416 return NULL;
1417 }
1418 const ResTable& res(am->getResources());
1419
1420 const ResTable::bag_entry* startOfBag;
1421 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1422 if (N < 0) {
1423 return NULL;
1424 }
1425
1426 jintArray array = env->NewIntArray(N * 2);
1427 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 res.unlockBag(startOfBag);
1429 return NULL;
1430 }
1431
1432 Res_value value;
1433 const ResTable::bag_entry* bag = startOfBag;
1434 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1435 jint stringIndex = -1;
1436 jint stringBlock = 0;
1437 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 // Take care of resolving the found resource to its final value.
1440 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1441 if (value.dataType == Res_value::TYPE_STRING) {
1442 stringIndex = value.data;
1443 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001444
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001445#if THROW_ON_BAD_ID
1446 if (stringBlock == BAD_INDEX) {
1447 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1448 return array;
1449 }
1450#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 //todo: It might be faster to allocate a C array to contain
1453 // the blocknums and indices, put them in there and then
1454 // do just one SetIntArrayRegion()
1455 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1456 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1457 j = j + 2;
1458 }
1459 res.unlockBag(startOfBag);
1460 return array;
1461}
1462
1463static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1464 jint arrayResId)
1465{
1466 AssetManager* am = assetManagerForJavaObject(env, clazz);
1467 if (am == NULL) {
1468 return NULL;
1469 }
1470 const ResTable& res(am->getResources());
1471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 const ResTable::bag_entry* startOfBag;
1473 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1474 if (N < 0) {
1475 return NULL;
1476 }
1477
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001478 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001479 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 res.unlockBag(startOfBag);
1481 return NULL;
1482 }
1483
1484 Res_value value;
1485 const ResTable::bag_entry* bag = startOfBag;
1486 size_t strLen = 0;
1487 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1488 value = bag->map.value;
1489 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 // Take care of resolving the found resource to its final value.
1492 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001493#if THROW_ON_BAD_ID
1494 if (block == BAD_INDEX) {
1495 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1496 return array;
1497 }
1498#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001500 const ResStringPool* pool = res.getTableStringBlock(block);
1501 const char* str8 = pool->string8At(value.data, &strLen);
1502 if (str8 != NULL) {
1503 str = env->NewStringUTF(str8);
1504 } else {
1505 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1506 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001507 }
1508
1509 // If one of our NewString{UTF} calls failed due to memory, an
1510 // exception will be pending.
1511 if (env->ExceptionCheck()) {
1512 res.unlockBag(startOfBag);
1513 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 }
Kenny Root780d2a12010-02-22 22:36:26 -08001515
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001516 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001517
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001518 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1519 // If we have a large amount of strings in our array, we might
1520 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001521 env->DeleteLocalRef(str);
1522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 }
1524 res.unlockBag(startOfBag);
1525 return array;
1526}
1527
1528static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1529 jint arrayResId)
1530{
1531 AssetManager* am = assetManagerForJavaObject(env, clazz);
1532 if (am == NULL) {
1533 return NULL;
1534 }
1535 const ResTable& res(am->getResources());
1536
1537 const ResTable::bag_entry* startOfBag;
1538 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1539 if (N < 0) {
1540 return NULL;
1541 }
1542
1543 jintArray array = env->NewIntArray(N);
1544 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 res.unlockBag(startOfBag);
1546 return NULL;
1547 }
1548
1549 Res_value value;
1550 const ResTable::bag_entry* bag = startOfBag;
1551 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1552 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 // Take care of resolving the found resource to its final value.
1555 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001556#if THROW_ON_BAD_ID
1557 if (block == BAD_INDEX) {
1558 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1559 return array;
1560 }
1561#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 if (value.dataType >= Res_value::TYPE_FIRST_INT
1563 && value.dataType <= Res_value::TYPE_LAST_INT) {
1564 int intVal = value.data;
1565 env->SetIntArrayRegion(array, i, 1, &intVal);
1566 }
1567 }
1568 res.unlockBag(startOfBag);
1569 return array;
1570}
1571
1572static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1573{
1574 AssetManager* am = new AssetManager();
1575 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001576 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 return;
1578 }
1579
1580 am->addDefaultAssets();
1581
Steve Block71f2cf12011-10-20 11:56:00 +01001582 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1584}
1585
1586static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1587{
1588 AssetManager* am = (AssetManager*)
1589 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001590 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 if (am != NULL) {
1592 delete am;
1593 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1594 }
1595}
1596
1597static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1598{
1599 return Asset::getGlobalCount();
1600}
1601
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001602static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1603{
1604 String8 alloc = Asset::getAssetAllocations();
1605 if (alloc.length() <= 0) {
1606 return NULL;
1607 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001608
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001609 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001610 return str;
1611}
1612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1614{
1615 return AssetManager::getGlobalCount();
1616}
1617
1618// ----------------------------------------------------------------------------
1619
1620/*
1621 * JNI registration.
1622 */
1623static JNINativeMethod gAssetManagerMethods[] = {
1624 /* name, signature, funcPtr */
1625
1626 // Basic asset stuff.
1627 { "openAsset", "(Ljava/lang/String;I)I",
1628 (void*) android_content_AssetManager_openAsset },
1629 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1630 (void*) android_content_AssetManager_openAssetFd },
1631 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1632 (void*) android_content_AssetManager_openNonAssetNative },
1633 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1634 (void*) android_content_AssetManager_openNonAssetFdNative },
1635 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1636 (void*) android_content_AssetManager_list },
1637 { "destroyAsset", "(I)V",
1638 (void*) android_content_AssetManager_destroyAsset },
1639 { "readAssetChar", "(I)I",
1640 (void*) android_content_AssetManager_readAssetChar },
1641 { "readAsset", "(I[BII)I",
1642 (void*) android_content_AssetManager_readAsset },
1643 { "seekAsset", "(IJI)J",
1644 (void*) android_content_AssetManager_seekAsset },
1645 { "getAssetLength", "(I)J",
1646 (void*) android_content_AssetManager_getAssetLength },
1647 { "getAssetRemainingLength", "(I)J",
1648 (void*) android_content_AssetManager_getAssetRemainingLength },
Dianne Hackbornf7be4802013-04-12 14:52:58 -07001649 { "addAssetPathNative", "(Ljava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 (void*) android_content_AssetManager_addAssetPath },
1651 { "isUpToDate", "()Z",
1652 (void*) android_content_AssetManager_isUpToDate },
1653
1654 // Resources.
1655 { "setLocale", "(Ljava/lang/String;)V",
1656 (void*) android_content_AssetManager_setLocale },
1657 { "getLocales", "()[Ljava/lang/String;",
1658 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001659 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 (void*) android_content_AssetManager_setConfiguration },
1661 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1662 (void*) android_content_AssetManager_getResourceIdentifier },
1663 { "getResourceName","(I)Ljava/lang/String;",
1664 (void*) android_content_AssetManager_getResourceName },
1665 { "getResourcePackageName","(I)Ljava/lang/String;",
1666 (void*) android_content_AssetManager_getResourcePackageName },
1667 { "getResourceTypeName","(I)Ljava/lang/String;",
1668 (void*) android_content_AssetManager_getResourceTypeName },
1669 { "getResourceEntryName","(I)Ljava/lang/String;",
1670 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001671 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 (void*) android_content_AssetManager_loadResourceValue },
1673 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1674 (void*) android_content_AssetManager_loadResourceBagValue },
1675 { "getStringBlockCount","()I",
1676 (void*) android_content_AssetManager_getStringBlockCount },
1677 { "getNativeStringBlock","(I)I",
1678 (void*) android_content_AssetManager_getNativeStringBlock },
1679 { "getCookieName","(I)Ljava/lang/String;",
1680 (void*) android_content_AssetManager_getCookieName },
1681
1682 // Themes.
1683 { "newTheme", "()I",
1684 (void*) android_content_AssetManager_newTheme },
1685 { "deleteTheme", "(I)V",
1686 (void*) android_content_AssetManager_deleteTheme },
1687 { "applyThemeStyle", "(IIZ)V",
1688 (void*) android_content_AssetManager_applyThemeStyle },
1689 { "copyTheme", "(II)V",
1690 (void*) android_content_AssetManager_copyTheme },
1691 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1692 (void*) android_content_AssetManager_loadThemeAttributeValue },
1693 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1694 (void*) android_content_AssetManager_dumpTheme },
1695 { "applyStyle","(IIII[I[I[I)Z",
1696 (void*) android_content_AssetManager_applyStyle },
1697 { "retrieveAttributes","(I[I[I[I)Z",
1698 (void*) android_content_AssetManager_retrieveAttributes },
1699 { "getArraySize","(I)I",
1700 (void*) android_content_AssetManager_getArraySize },
1701 { "retrieveArray","(I[I)I",
1702 (void*) android_content_AssetManager_retrieveArray },
1703
1704 // XML files.
1705 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1706 (void*) android_content_AssetManager_openXmlAssetNative },
1707
1708 // Arrays.
1709 { "getArrayStringResource","(I)[Ljava/lang/String;",
1710 (void*) android_content_AssetManager_getArrayStringResource },
1711 { "getArrayStringInfo","(I)[I",
1712 (void*) android_content_AssetManager_getArrayStringInfo },
1713 { "getArrayIntResource","(I)[I",
1714 (void*) android_content_AssetManager_getArrayIntResource },
1715
1716 // Bookkeeping.
1717 { "init", "()V",
1718 (void*) android_content_AssetManager_init },
1719 { "destroy", "()V",
1720 (void*) android_content_AssetManager_destroy },
1721 { "getGlobalAssetCount", "()I",
1722 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001723 { "getAssetAllocations", "()Ljava/lang/String;",
1724 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 { "getGlobalAssetManagerCount", "()I",
1726 (void*) android_content_AssetManager_getGlobalAssetCount },
1727};
1728
1729int register_android_content_AssetManager(JNIEnv* env)
1730{
1731 jclass typedValue = env->FindClass("android/util/TypedValue");
1732 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1733 gTypedValueOffsets.mType
1734 = env->GetFieldID(typedValue, "type", "I");
1735 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1736 gTypedValueOffsets.mData
1737 = env->GetFieldID(typedValue, "data", "I");
1738 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1739 gTypedValueOffsets.mString
1740 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1741 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1742 gTypedValueOffsets.mAssetCookie
1743 = env->GetFieldID(typedValue, "assetCookie", "I");
1744 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1745 gTypedValueOffsets.mResourceId
1746 = env->GetFieldID(typedValue, "resourceId", "I");
1747 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1748 gTypedValueOffsets.mChangingConfigurations
1749 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1750 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1751 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1752 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1753
1754 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1755 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1756 gAssetFileDescriptorOffsets.mFd
1757 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1758 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1759 gAssetFileDescriptorOffsets.mStartOffset
1760 = env->GetFieldID(assetFd, "mStartOffset", "J");
1761 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1762 gAssetFileDescriptorOffsets.mLength
1763 = env->GetFieldID(assetFd, "mLength", "J");
1764 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1765
1766 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1767 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1768 gAssetManagerOffsets.mObject
1769 = env->GetFieldID(assetManager, "mObject", "I");
1770 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1771
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001772 jclass stringClass = env->FindClass("java/lang/String");
1773 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1774 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001775 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 -08001776
1777 return AndroidRuntime::registerNativeMethods(env,
1778 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1779}
1780
1781}; // namespace android