blob: 9dde701adb1b9d6cbd13d2f17a598ebb7e97009b [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
Mårten Kongstad48d22322014-01-31 14:43:27 +010038#include <private/android_filesystem_config.h> // for AID_SYSTEM
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040#include <stdio.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010041#include <sys/types.h>
42#include <sys/wait.h>
43
44#include <linux/capability.h>
45extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
46extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
49namespace android {
50
51// ----------------------------------------------------------------------------
52
53static struct typedvalue_offsets_t
54{
55 jfieldID mType;
56 jfieldID mData;
57 jfieldID mString;
58 jfieldID mAssetCookie;
59 jfieldID mResourceId;
60 jfieldID mChangingConfigurations;
61 jfieldID mDensity;
62} gTypedValueOffsets;
63
64static struct assetfiledescriptor_offsets_t
65{
66 jfieldID mFd;
67 jfieldID mStartOffset;
68 jfieldID mLength;
69} gAssetFileDescriptorOffsets;
70
71static struct assetmanager_offsets_t
72{
73 jfieldID mObject;
74} gAssetManagerOffsets;
75
76jclass g_stringClass = NULL;
77
78// ----------------------------------------------------------------------------
79
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -070081 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 STYLE_TYPE = 0,
83 STYLE_DATA = 1,
84 STYLE_ASSET_COOKIE = 2,
85 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -070086 STYLE_CHANGING_CONFIGURATIONS = 4,
87 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088};
89
90static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
91 const Res_value& value, uint32_t ref, ssize_t block,
92 uint32_t typeSpecFlags, ResTable_config* config = NULL);
93
94jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
95 const Res_value& value, uint32_t ref, ssize_t block,
96 uint32_t typeSpecFlags, ResTable_config* config)
97{
98 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
99 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
Ashok Bhat896043d2014-01-17 16:02:38 +0000100 static_cast<jint>(table->getTableCookie(block)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
102 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
103 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
104 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
105 typeSpecFlags);
106 if (config != NULL) {
107 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
108 }
109 return block;
110}
111
Mårten Kongstad48d22322014-01-31 14:43:27 +0100112// This is called by zygote (running as user root) as part of preloadResources.
113static void verifySystemIdmaps()
114{
115 pid_t pid;
116 char system_id[10];
117
118 snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
119
120 switch (pid = fork()) {
121 case -1:
122 ALOGE("failed to fork for idmap: %s", strerror(errno));
123 break;
124 case 0: // child
125 {
126 struct __user_cap_header_struct capheader;
127 struct __user_cap_data_struct capdata;
128
129 memset(&capheader, 0, sizeof(capheader));
130 memset(&capdata, 0, sizeof(capdata));
131
132 capheader.version = _LINUX_CAPABILITY_VERSION;
133 capheader.pid = 0;
134
135 if (capget(&capheader, &capdata) != 0) {
136 ALOGE("capget: %s\n", strerror(errno));
137 exit(1);
138 }
139
140 capdata.effective = capdata.permitted;
141 if (capset(&capheader, &capdata) != 0) {
142 ALOGE("capset: %s\n", strerror(errno));
143 exit(1);
144 }
145
146 if (setgid(AID_SYSTEM) != 0) {
147 ALOGE("setgid: %s\n", strerror(errno));
148 exit(1);
149 }
150
151 if (setuid(AID_SYSTEM) != 0) {
152 ALOGE("setuid: %s\n", strerror(errno));
153 exit(1);
154 }
155
156 execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
157 AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
158 AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
159 ALOGE("failed to execl for idmap: %s", strerror(errno));
160 exit(1); // should never get here
161 }
162 break;
163 default: // parent
164 waitpid(pid, NULL, 0);
165 break;
166 }
167}
168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169// ----------------------------------------------------------------------------
170
171// this guy is exported to other jni routines
172AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
173{
Ashok Bhat896043d2014-01-17 16:02:38 +0000174 jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
175 AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 if (am != NULL) {
177 return am;
178 }
179 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
180 return NULL;
181}
182
Ashok Bhat896043d2014-01-17 16:02:38 +0000183static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 jstring fileName, jint mode)
185{
186 AssetManager* am = assetManagerForJavaObject(env, clazz);
187 if (am == NULL) {
188 return 0;
189 }
190
Steve Block71f2cf12011-10-20 11:56:00 +0100191 ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Elliott Hughes69a017b2011-04-08 14:10:28 -0700193 ScopedUtfChars fileName8(env, fileName);
194 if (fileName8.c_str() == NULL) {
Ashok Bhat896043d2014-01-17 16:02:38 +0000195 jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 return -1;
197 }
198
199 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
200 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700201 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 return -1;
203 }
204
Elliott Hughes69a017b2011-04-08 14:10:28 -0700205 Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
207 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700208 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 return -1;
210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211
212 //printf("Created Asset Stream: %p\n", a);
213
Ashok Bhat896043d2014-01-17 16:02:38 +0000214 return reinterpret_cast<jlong>(a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215}
216
217static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
218{
Kenny Rootddb76c42010-11-24 12:56:06 -0800219 off64_t startOffset, length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 int fd = a->openFileDescriptor(&startOffset, &length);
221 delete a;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 if (fd < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700224 jniThrowException(env, "java/io/FileNotFoundException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 "This file can not be opened as a file descriptor; it is probably compressed");
226 return NULL;
227 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
230 if (offsets == NULL) {
231 close(fd);
232 return NULL;
233 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 offsets[0] = startOffset;
236 offsets[1] = length;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700239
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700240 jobject fileDesc = jniCreateFileDescriptor(env, fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 if (fileDesc == NULL) {
242 close(fd);
243 return NULL;
244 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 return newParcelFileDescriptor(env, fileDesc);
247}
248
249static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
250 jstring fileName, jlongArray outOffsets)
251{
252 AssetManager* am = assetManagerForJavaObject(env, clazz);
253 if (am == NULL) {
254 return NULL;
255 }
256
Steve Block71f2cf12011-10-20 11:56:00 +0100257 ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
Elliott Hughes69a017b2011-04-08 14:10:28 -0700259 ScopedUtfChars fileName8(env, fileName);
260 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 return NULL;
262 }
263
Elliott Hughes69a017b2011-04-08 14:10:28 -0700264 Asset* a = am->open(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
Ashok Bhat896043d2014-01-17 16:02:38 +0000276static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 jint cookie,
278 jstring fileName,
279 jint mode)
280{
281 AssetManager* am = assetManagerForJavaObject(env, clazz);
282 if (am == NULL) {
283 return 0;
284 }
285
Steve Block71f2cf12011-10-20 11:56:00 +0100286 ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
Elliott Hughes69a017b2011-04-08 14:10:28 -0700288 ScopedUtfChars fileName8(env, fileName);
289 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 return -1;
291 }
292
293 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
294 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700295 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 return -1;
297 }
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000300 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
301 (Asset::AccessMode)mode)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700302 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700305 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 return -1;
307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308
309 //printf("Created Asset Stream: %p\n", a);
310
Ashok Bhat896043d2014-01-17 16:02:38 +0000311 return reinterpret_cast<jlong>(a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312}
313
314static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
315 jint cookie,
316 jstring fileName,
317 jlongArray outOffsets)
318{
319 AssetManager* am = assetManagerForJavaObject(env, clazz);
320 if (am == NULL) {
321 return NULL;
322 }
323
Steve Block71f2cf12011-10-20 11:56:00 +0100324 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325
Elliott Hughes69a017b2011-04-08 14:10:28 -0700326 ScopedUtfChars fileName8(env, fileName);
327 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 return NULL;
329 }
330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000332 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700333 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334
335 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700336 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 return NULL;
338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339
340 //printf("Created Asset Stream: %p\n", a);
341
342 return returnParcelFileDescriptor(env, a, outOffsets);
343}
344
345static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
346 jstring fileName)
347{
348 AssetManager* am = assetManagerForJavaObject(env, clazz);
349 if (am == NULL) {
350 return NULL;
351 }
352
Elliott Hughes69a017b2011-04-08 14:10:28 -0700353 ScopedUtfChars fileName8(env, fileName);
354 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 return NULL;
356 }
357
Elliott Hughes69a017b2011-04-08 14:10:28 -0700358 AssetDir* dir = am->openDir(fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359
360 if (dir == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700361 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 return NULL;
363 }
364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 size_t N = dir->getFileCount();
366
367 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +0100368 g_stringClass, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 delete dir;
371 return NULL;
372 }
373
374 for (size_t i=0; i<N; i++) {
375 const String8& name = dir->getFileName(i);
376 jstring str = env->NewStringUTF(name.string());
377 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 delete dir;
379 return NULL;
380 }
381 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700382 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
384
385 delete dir;
386
387 return array;
388}
389
390static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000391 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392{
Ashok Bhat896043d2014-01-17 16:02:38 +0000393 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
395 //printf("Destroying Asset Stream: %p\n", a);
396
397 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700398 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return;
400 }
401
402 delete a;
403}
404
405static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000406 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407{
Ashok Bhat896043d2014-01-17 16:02:38 +0000408 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409
410 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700411 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 return -1;
413 }
414
415 uint8_t b;
416 ssize_t res = a->read(&b, 1);
417 return res == 1 ? b : -1;
418}
419
420static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000421 jlong assetHandle, jbyteArray bArray,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 jint off, jint len)
423{
Ashok Bhat896043d2014-01-17 16:02:38 +0000424 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425
426 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700427 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 return -1;
429 }
430
431 if (len == 0) {
432 return 0;
433 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 jsize bLen = env->GetArrayLength(bArray);
436 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700437 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 return -1;
439 }
440
441 jbyte* b = env->GetByteArrayElements(bArray, NULL);
442 ssize_t res = a->read(b+off, len);
443 env->ReleaseByteArrayElements(bArray, b, 0);
444
Ashok Bhat896043d2014-01-17 16:02:38 +0000445 if (res > 0) return static_cast<jint>(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446
447 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700448 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 }
450 return -1;
451}
452
453static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000454 jlong assetHandle,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 jlong offset, jint whence)
456{
Ashok Bhat896043d2014-01-17 16:02:38 +0000457 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458
459 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700460 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 return -1;
462 }
463
464 return a->seek(
465 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
466}
467
468static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000469 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470{
Ashok Bhat896043d2014-01-17 16:02:38 +0000471 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
473 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700474 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 return -1;
476 }
477
478 return a->getLength();
479}
480
481static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000482 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483{
Ashok Bhat896043d2014-01-17 16:02:38 +0000484 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485
486 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700487 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 return -1;
489 }
490
491 return a->getRemainingLength();
492}
493
494static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
495 jstring path)
496{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700497 ScopedUtfChars path8(env, path);
498 if (path8.c_str() == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800499 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 }
501
502 AssetManager* am = assetManagerForJavaObject(env, clazz);
503 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800504 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 }
506
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000507 int32_t cookie;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700508 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000510 return (res) ? static_cast<jint>(cookie) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511}
512
Mårten Kongstad48d22322014-01-31 14:43:27 +0100513static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
514 jstring idmapPath)
515{
516 ScopedUtfChars idmapPath8(env, idmapPath);
517 if (idmapPath8.c_str() == NULL) {
518 return 0;
519 }
520
521 AssetManager* am = assetManagerForJavaObject(env, clazz);
522 if (am == NULL) {
523 return 0;
524 }
525
526 int32_t cookie;
527 bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
528
529 return (res) ? (jint)cookie : 0;
530}
531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
533{
534 AssetManager* am = assetManagerForJavaObject(env, clazz);
535 if (am == NULL) {
536 return JNI_TRUE;
537 }
538 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
539}
540
541static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
542 jstring locale)
543{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700544 ScopedUtfChars locale8(env, locale);
545 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 return;
547 }
548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 AssetManager* am = assetManagerForJavaObject(env, clazz);
550 if (am == NULL) {
551 return;
552 }
553
Elliott Hughes69a017b2011-04-08 14:10:28 -0700554 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555}
556
557static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
558{
559 Vector<String8> locales;
560
561 AssetManager* am = assetManagerForJavaObject(env, clazz);
562 if (am == NULL) {
563 return NULL;
564 }
565
566 am->getLocales(&locales);
567
568 const int N = locales.size();
569
570 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
571 if (result == NULL) {
572 return NULL;
573 }
574
575 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700576 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700577 if (str == NULL) {
578 return NULL;
579 }
580 env->SetObjectArrayElement(result, i, str);
581 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583
584 return result;
585}
586
587static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
588 jint mcc, jint mnc,
589 jstring locale, jint orientation,
590 jint touchscreen, jint density,
591 jint keyboard, jint keyboardHidden,
592 jint navigation,
593 jint screenWidth, jint screenHeight,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700594 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700595 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100596 jint screenLayout, jint uiMode,
597 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598{
599 AssetManager* am = assetManagerForJavaObject(env, clazz);
600 if (am == NULL) {
601 return;
602 }
603
604 ResTable_config config;
605 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 config.mcc = (uint16_t)mcc;
610 config.mnc = (uint16_t)mnc;
611 config.orientation = (uint8_t)orientation;
612 config.touchscreen = (uint8_t)touchscreen;
613 config.density = (uint16_t)density;
614 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700615 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 config.navigation = (uint8_t)navigation;
617 config.screenWidth = (uint16_t)screenWidth;
618 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700619 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700620 config.screenWidthDp = (uint16_t)screenWidthDp;
621 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700622 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100623 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 config.sdkVersion = (uint16_t)sdkVersion;
625 config.minorVersion = 0;
626 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
629}
630
631static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
632 jstring name,
633 jstring defType,
634 jstring defPackage)
635{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700636 ScopedStringChars name16(env, name);
637 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 return 0;
639 }
640
641 AssetManager* am = assetManagerForJavaObject(env, clazz);
642 if (am == NULL) {
643 return 0;
644 }
645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 const char16_t* defType16 = defType
647 ? env->GetStringChars(defType, NULL) : NULL;
648 jsize defTypeLen = defType
649 ? env->GetStringLength(defType) : 0;
650 const char16_t* defPackage16 = defPackage
651 ? env->GetStringChars(defPackage, NULL) : NULL;
652 jsize defPackageLen = defPackage
653 ? env->GetStringLength(defPackage) : 0;
654
655 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700656 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657
658 if (defPackage16) {
659 env->ReleaseStringChars(defPackage, defPackage16);
660 }
661 if (defType16) {
662 env->ReleaseStringChars(defType, defType16);
663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664
665 return ident;
666}
667
668static jstring android_content_AssetManager_getResourceName(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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 String16 str;
682 if (name.package != NULL) {
683 str.setTo(name.package, name.packageLen);
684 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700685 if (name.type8 != NULL || name.type != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 if (str.size() > 0) {
687 char16_t div = ':';
688 str.append(&div, 1);
689 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700690 if (name.type8 != NULL) {
691 str.append(String16(name.type8, name.typeLen));
692 } else {
693 str.append(name.type, name.typeLen);
694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700696 if (name.name8 != NULL || name.name != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 if (str.size() > 0) {
698 char16_t div = '/';
699 str.append(&div, 1);
700 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700701 if (name.name8 != NULL) {
702 str.append(String16(name.name8, name.nameLen));
703 } else {
704 str.append(name.name, name.nameLen);
705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 return env->NewString((const jchar*)str.string(), str.size());
709}
710
711static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
712 jint resid)
713{
714 AssetManager* am = assetManagerForJavaObject(env, clazz);
715 if (am == NULL) {
716 return NULL;
717 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700720 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 return NULL;
722 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 if (name.package != NULL) {
725 return env->NewString((const jchar*)name.package, name.packageLen);
726 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 return NULL;
729}
730
731static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
732 jint resid)
733{
734 AssetManager* am = assetManagerForJavaObject(env, clazz);
735 if (am == NULL) {
736 return NULL;
737 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700740 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 return NULL;
742 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700743
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700744 if (name.type8 != NULL) {
745 return env->NewStringUTF(name.type8);
746 }
747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 if (name.type != NULL) {
749 return env->NewString((const jchar*)name.type, name.typeLen);
750 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 return NULL;
753}
754
755static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
756 jint resid)
757{
758 AssetManager* am = assetManagerForJavaObject(env, clazz);
759 if (am == NULL) {
760 return NULL;
761 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700764 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 return NULL;
766 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700767
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700768 if (name.name8 != NULL) {
769 return env->NewStringUTF(name.name8);
770 }
771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 if (name.name != NULL) {
773 return env->NewString((const jchar*)name.name, name.nameLen);
774 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 return NULL;
777}
778
779static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
780 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700781 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 jobject outValue,
783 jboolean resolve)
784{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800785 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800786 jniThrowNullPointerException(env, "outValue");
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700787 return 0;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 AssetManager* am = assetManagerForJavaObject(env, clazz);
790 if (am == NULL) {
791 return 0;
792 }
793 const ResTable& res(am->getResources());
794
795 Res_value value;
796 ResTable_config config;
797 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700798 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800799#if THROW_ON_BAD_ID
800 if (block == BAD_INDEX) {
801 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
802 return 0;
803 }
804#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 uint32_t ref = ident;
806 if (resolve) {
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700807 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800808#if THROW_ON_BAD_ID
809 if (block == BAD_INDEX) {
810 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
811 return 0;
812 }
813#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000815 if (block >= 0) {
816 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
817 }
818
819 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820}
821
822static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
823 jint ident, jint bagEntryId,
824 jobject outValue, jboolean resolve)
825{
826 AssetManager* am = assetManagerForJavaObject(env, clazz);
827 if (am == NULL) {
828 return 0;
829 }
830 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 // Now lock down the resource object and start pulling stuff from it.
833 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 ssize_t block = -1;
836 Res_value value;
837
838 const ResTable::bag_entry* entry = NULL;
839 uint32_t typeSpecFlags;
840 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
841
842 for (ssize_t i=0; i<entryCount; i++) {
843 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
844 block = entry->stringBlock;
845 value = entry->map.value;
846 }
847 entry++;
848 }
849
850 res.unlock();
851
852 if (block < 0) {
Ashok Bhat896043d2014-01-17 16:02:38 +0000853 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 uint32_t ref = ident;
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 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000866 if (block >= 0) {
867 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
868 }
869
870 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871}
872
873static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
874{
875 AssetManager* am = assetManagerForJavaObject(env, clazz);
876 if (am == NULL) {
877 return 0;
878 }
879 return am->getResources().getTableCount();
880}
881
Ashok Bhat896043d2014-01-17 16:02:38 +0000882static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 jint block)
884{
885 AssetManager* am = assetManagerForJavaObject(env, clazz);
886 if (am == NULL) {
887 return 0;
888 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000889 return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890}
891
892static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
893 jint cookie)
894{
895 AssetManager* am = assetManagerForJavaObject(env, clazz);
896 if (am == NULL) {
897 return NULL;
898 }
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000899 String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700901 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 return NULL;
903 }
904 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 return str;
906}
907
Ashok Bhat896043d2014-01-17 16:02:38 +0000908static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909{
910 AssetManager* am = assetManagerForJavaObject(env, clazz);
911 if (am == NULL) {
912 return 0;
913 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000914 return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915}
916
917static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000918 jlong themeHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919{
Ashok Bhat896043d2014-01-17 16:02:38 +0000920 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 delete theme;
922}
923
924static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000925 jlong themeHandle,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 jint styleRes,
927 jboolean force)
928{
Ashok Bhat896043d2014-01-17 16:02:38 +0000929 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 theme->applyStyle(styleRes, force ? true : false);
931}
932
933static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000934 jlong destHandle, jlong srcHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935{
Ashok Bhat896043d2014-01-17 16:02:38 +0000936 ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
937 ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 dest->setTo(*src);
939}
940
941static jint android_content_AssetManager_loadThemeAttributeValue(
Ashok Bhat896043d2014-01-17 16:02:38 +0000942 JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943{
Ashok Bhat896043d2014-01-17 16:02:38 +0000944 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 const ResTable& res(theme->getResTable());
946
947 Res_value value;
948 // XXX value could be different in different configs!
949 uint32_t typeSpecFlags = 0;
950 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
951 uint32_t ref = 0;
952 if (resolve) {
953 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800954#if THROW_ON_BAD_ID
955 if (block == BAD_INDEX) {
956 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
957 return 0;
958 }
959#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 }
961 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
962}
963
964static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000965 jlong themeHandle, jint pri,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 jstring tag, jstring prefix)
967{
Ashok Bhat896043d2014-01-17 16:02:38 +0000968 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 // XXX Need to use params.
972 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973}
974
Alan Viverette52b999f2014-03-24 18:00:26 -0700975static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
976 jlong themeToken,
977 jint defStyleAttr,
978 jint defStyleRes,
979 jintArray inValues,
980 jintArray attrs,
981 jintArray outValues,
982 jintArray outIndices)
983{
984 if (themeToken == 0) {
985 jniThrowNullPointerException(env, "theme token");
986 return JNI_FALSE;
987 }
988 if (attrs == NULL) {
989 jniThrowNullPointerException(env, "attrs");
990 return JNI_FALSE;
991 }
992 if (outValues == NULL) {
993 jniThrowNullPointerException(env, "out values");
994 return JNI_FALSE;
995 }
996
997 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
998 themeToken, defStyleAttr, defStyleRes));
999
1000 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1001 const ResTable& res = theme->getResTable();
1002 ResTable_config config;
1003 Res_value value;
1004
1005 const jsize NI = env->GetArrayLength(attrs);
1006 const jsize NV = env->GetArrayLength(outValues);
1007 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1008 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1009 return JNI_FALSE;
1010 }
1011
1012 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1013 if (src == NULL) {
1014 return JNI_FALSE;
1015 }
1016
1017 jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1018 const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1019
1020 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1021 jint* dest = baseDest;
1022 if (dest == NULL) {
1023 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1024 return JNI_FALSE;
1025 }
1026
1027 jint* indices = NULL;
1028 int indicesIdx = 0;
1029 if (outIndices != NULL) {
1030 if (env->GetArrayLength(outIndices) > NI) {
1031 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1032 }
1033 }
1034
1035 // Load default style from attribute, if specified...
1036 uint32_t defStyleBagTypeSetFlags = 0;
1037 if (defStyleAttr != 0) {
1038 Res_value value;
1039 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1040 if (value.dataType == Res_value::TYPE_REFERENCE) {
1041 defStyleRes = value.data;
1042 }
1043 }
1044 }
1045
1046 // Now lock down the resource object and start pulling stuff from it.
1047 res.lock();
1048
1049 // Retrieve the default style bag, if requested.
1050 const ResTable::bag_entry* defStyleEnt = NULL;
1051 uint32_t defStyleTypeSetFlags = 0;
1052 ssize_t bagOff = defStyleRes != 0
1053 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
1054 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1055 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1056 (bagOff >= 0 ? bagOff : 0);;
1057
1058 // Now iterate through all of the attributes that the client has requested,
1059 // filling in each with whatever data we can find.
1060 ssize_t block = 0;
1061 uint32_t typeSetFlags;
1062 for (jsize ii=0; ii<NI; ii++) {
1063 const uint32_t curIdent = (uint32_t)src[ii];
1064
1065 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1066
1067 // Try to find a value for this attribute... we prioritize values
1068 // coming from, first XML attributes, then XML style, then default
1069 // style, and finally the theme.
1070 value.dataType = Res_value::TYPE_NULL;
1071 value.data = 0;
1072 typeSetFlags = 0;
1073 config.density = 0;
1074
1075 // Retrieve the current input value if available.
1076 if (NSV > 0 && srcValues[ii] != 0) {
1077 block = -1;
1078 value.dataType = Res_value::TYPE_ATTRIBUTE;
1079 value.data = srcValues[ii];
1080 DEBUG_STYLES(LOGI("-> From values: type=0x%x, data=0x%08x",
1081 value.dataType, value.data));
1082 }
1083
1084 // Skip through the default style values until the end or the next possible match.
1085 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1086 defStyleEnt++;
1087 }
1088 // Retrieve the current default style attribute if it matches, and step to next.
1089 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1090 if (value.dataType == Res_value::TYPE_NULL) {
1091 block = defStyleEnt->stringBlock;
1092 typeSetFlags = defStyleTypeSetFlags;
1093 value = defStyleEnt->map.value;
1094 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1095 value.dataType, value.data));
1096 }
1097 defStyleEnt++;
1098 }
1099
1100 uint32_t resid = 0;
1101 if (value.dataType != Res_value::TYPE_NULL) {
1102 // Take care of resolving the found resource to its final value.
1103 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1104 &resid, &typeSetFlags, &config);
1105 if (newBlock >= 0) block = newBlock;
1106 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1107 value.dataType, value.data));
1108 } else {
1109 // If we still don't have a value for this attribute, try to find
1110 // it in the theme!
1111 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1112 if (newBlock >= 0) {
1113 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1114 value.dataType, value.data));
1115 newBlock = res.resolveReference(&value, block, &resid,
1116 &typeSetFlags, &config);
1117#if THROW_ON_BAD_ID
1118 if (newBlock == BAD_INDEX) {
1119 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1120 return JNI_FALSE;
1121 }
1122#endif
1123 if (newBlock >= 0) block = newBlock;
1124 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1125 value.dataType, value.data));
1126 }
1127 }
1128
1129 // Deal with the special @null value -- it turns back to TYPE_NULL.
1130 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1131 DEBUG_STYLES(LOGI("-> Setting to @null!"));
1132 value.dataType = Res_value::TYPE_NULL;
1133 block = -1;
1134 }
1135
1136 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1137 curIdent, value.dataType, value.data));
1138
1139 // Write the final value back to Java.
1140 dest[STYLE_TYPE] = value.dataType;
1141 dest[STYLE_DATA] = value.data;
1142 dest[STYLE_ASSET_COOKIE] =
1143 block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1144 dest[STYLE_RESOURCE_ID] = resid;
1145 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1146 dest[STYLE_DENSITY] = config.density;
1147
1148 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1149 indicesIdx++;
1150 indices[indicesIdx] = ii;
1151 }
1152
1153 dest += STYLE_NUM_ENTRIES;
1154 }
1155
1156 res.unlock();
1157
1158 if (indices != NULL) {
1159 indices[0] = indicesIdx;
1160 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1161 }
1162 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1163 env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1164 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1165
1166 return JNI_TRUE;
1167}
1168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001170 jlong themeToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 jint defStyleAttr,
1172 jint defStyleRes,
Ashok Bhat896043d2014-01-17 16:02:38 +00001173 jlong xmlParserToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 jintArray attrs,
1175 jintArray outValues,
1176 jintArray outIndices)
1177{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001178 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001179 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001180 return JNI_FALSE;
1181 }
1182 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001183 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001184 return JNI_FALSE;
1185 }
1186 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001187 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 return JNI_FALSE;
1189 }
1190
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001191 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
1192 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -07001193
Ashok Bhat896043d2014-01-17 16:02:38 +00001194 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 const ResTable& res = theme->getResTable();
Ashok Bhat896043d2014-01-17 16:02:38 +00001196 ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
Dianne Hackborn0d221012009-07-29 15:41:19 -07001197 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 Res_value value;
1199
1200 const jsize NI = env->GetArrayLength(attrs);
1201 const jsize NV = env->GetArrayLength(outValues);
1202 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001203 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 return JNI_FALSE;
1205 }
1206
1207 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1208 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 return JNI_FALSE;
1210 }
1211
1212 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1213 jint* dest = baseDest;
1214 if (dest == NULL) {
1215 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 return JNI_FALSE;
1217 }
1218
1219 jint* indices = NULL;
1220 int indicesIdx = 0;
1221 if (outIndices != NULL) {
1222 if (env->GetArrayLength(outIndices) > NI) {
1223 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1224 }
1225 }
1226
1227 // Load default style from attribute, if specified...
1228 uint32_t defStyleBagTypeSetFlags = 0;
1229 if (defStyleAttr != 0) {
1230 Res_value value;
1231 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1232 if (value.dataType == Res_value::TYPE_REFERENCE) {
1233 defStyleRes = value.data;
1234 }
1235 }
1236 }
1237
1238 // Retrieve the style class associated with the current XML tag.
1239 int style = 0;
1240 uint32_t styleBagTypeSetFlags = 0;
1241 if (xmlParser != NULL) {
1242 ssize_t idx = xmlParser->indexOfStyle();
1243 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1244 if (value.dataType == value.TYPE_ATTRIBUTE) {
1245 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1246 value.dataType = Res_value::TYPE_NULL;
1247 }
1248 }
1249 if (value.dataType == value.TYPE_REFERENCE) {
1250 style = value.data;
1251 }
1252 }
1253 }
1254
1255 // Now lock down the resource object and start pulling stuff from it.
1256 res.lock();
1257
1258 // Retrieve the default style bag, if requested.
1259 const ResTable::bag_entry* defStyleEnt = NULL;
1260 uint32_t defStyleTypeSetFlags = 0;
1261 ssize_t bagOff = defStyleRes != 0
1262 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
1263 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1264 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1265 (bagOff >= 0 ? bagOff : 0);
1266
1267 // Retrieve the style class bag, if requested.
1268 const ResTable::bag_entry* styleEnt = NULL;
1269 uint32_t styleTypeSetFlags = 0;
1270 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
1271 styleTypeSetFlags |= styleBagTypeSetFlags;
1272 const ResTable::bag_entry* endStyleEnt = styleEnt +
1273 (bagOff >= 0 ? bagOff : 0);
1274
1275 // Retrieve the XML attributes, if requested.
1276 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
1277 jsize ix=0;
1278 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
1279
1280 static const ssize_t kXmlBlock = 0x10000000;
1281
1282 // Now iterate through all of the attributes that the client has requested,
1283 // filling in each with whatever data we can find.
1284 ssize_t block = 0;
1285 uint32_t typeSetFlags;
1286 for (jsize ii=0; ii<NI; ii++) {
1287 const uint32_t curIdent = (uint32_t)src[ii];
1288
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001289 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -07001290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 // Try to find a value for this attribute... we prioritize values
1292 // coming from, first XML attributes, then XML style, then default
1293 // style, and finally the theme.
1294 value.dataType = Res_value::TYPE_NULL;
1295 value.data = 0;
1296 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001297 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298
1299 // Skip through XML attributes until the end or the next possible match.
1300 while (ix < NX && curIdent > curXmlAttr) {
1301 ix++;
1302 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1303 }
1304 // Retrieve the current XML attribute if it matches, and step to next.
1305 if (ix < NX && curIdent == curXmlAttr) {
1306 block = kXmlBlock;
1307 xmlParser->getAttributeValue(ix, &value);
1308 ix++;
1309 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001310 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1311 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
1313
1314 // Skip through the style values until the end or the next possible match.
1315 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1316 styleEnt++;
1317 }
1318 // Retrieve the current style attribute if it matches, and step to next.
1319 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1320 if (value.dataType == Res_value::TYPE_NULL) {
1321 block = styleEnt->stringBlock;
1322 typeSetFlags = styleTypeSetFlags;
1323 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001324 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1325 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 }
1327 styleEnt++;
1328 }
1329
1330 // Skip through the default style values until the end or the next possible match.
1331 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1332 defStyleEnt++;
1333 }
1334 // Retrieve the current default style attribute if it matches, and step to next.
1335 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1336 if (value.dataType == Res_value::TYPE_NULL) {
1337 block = defStyleEnt->stringBlock;
1338 typeSetFlags = defStyleTypeSetFlags;
1339 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001340 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1341 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
1343 defStyleEnt++;
1344 }
1345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 uint32_t resid = 0;
1347 if (value.dataType != Res_value::TYPE_NULL) {
1348 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001349 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1350 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001352 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1353 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 } else {
1355 // If we still don't have a value for this attribute, try to find
1356 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1358 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001359 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1360 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001361 newBlock = res.resolveReference(&value, block, &resid,
1362 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001363#if THROW_ON_BAD_ID
1364 if (newBlock == BAD_INDEX) {
1365 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1366 return JNI_FALSE;
1367 }
1368#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001370 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1371 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 }
1373 }
1374
1375 // Deal with the special @null value -- it turns back to TYPE_NULL.
1376 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001377 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001379 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 }
1381
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001382 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1383 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384
1385 // Write the final value back to Java.
1386 dest[STYLE_TYPE] = value.dataType;
1387 dest[STYLE_DATA] = value.data;
1388 dest[STYLE_ASSET_COOKIE] =
Ashok Bhat896043d2014-01-17 16:02:38 +00001389 block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 dest[STYLE_RESOURCE_ID] = resid;
1391 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001392 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1395 indicesIdx++;
1396 indices[indicesIdx] = ii;
1397 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 dest += STYLE_NUM_ENTRIES;
1400 }
1401
1402 res.unlock();
1403
1404 if (indices != NULL) {
1405 indices[0] = indicesIdx;
1406 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1407 }
1408 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1409 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1410
1411 return JNI_TRUE;
1412}
1413
1414static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001415 jlong xmlParserToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 jintArray attrs,
1417 jintArray outValues,
1418 jintArray outIndices)
1419{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001420 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001421 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001422 return JNI_FALSE;
1423 }
1424 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001425 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001426 return JNI_FALSE;
1427 }
1428 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001429 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 return JNI_FALSE;
1431 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 AssetManager* am = assetManagerForJavaObject(env, clazz);
1434 if (am == NULL) {
1435 return JNI_FALSE;
1436 }
1437 const ResTable& res(am->getResources());
1438 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001439 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 const jsize NI = env->GetArrayLength(attrs);
1443 const jsize NV = env->GetArrayLength(outValues);
1444 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001445 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 return JNI_FALSE;
1447 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1450 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 return JNI_FALSE;
1452 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1455 jint* dest = baseDest;
1456 if (dest == NULL) {
1457 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 return JNI_FALSE;
1459 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 jint* indices = NULL;
1462 int indicesIdx = 0;
1463 if (outIndices != NULL) {
1464 if (env->GetArrayLength(outIndices) > NI) {
1465 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1466 }
1467 }
1468
1469 // Now lock down the resource object and start pulling stuff from it.
1470 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 // Retrieve the XML attributes, if requested.
1473 const jsize NX = xmlParser->getAttributeCount();
1474 jsize ix=0;
1475 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 // Now iterate through all of the attributes that the client has requested,
1480 // filling in each with whatever data we can find.
1481 ssize_t block = 0;
1482 uint32_t typeSetFlags;
1483 for (jsize ii=0; ii<NI; ii++) {
1484 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 // Try to find a value for this attribute...
1487 value.dataType = Res_value::TYPE_NULL;
1488 value.data = 0;
1489 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001490 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 // Skip through XML attributes until the end or the next possible match.
1493 while (ix < NX && curIdent > curXmlAttr) {
1494 ix++;
1495 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1496 }
1497 // Retrieve the current XML attribute if it matches, and step to next.
1498 if (ix < NX && curIdent == curXmlAttr) {
1499 block = kXmlBlock;
1500 xmlParser->getAttributeValue(ix, &value);
1501 ix++;
1502 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1503 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1506 uint32_t resid = 0;
1507 if (value.dataType != Res_value::TYPE_NULL) {
1508 // Take care of resolving the found resource to its final value.
1509 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001510 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1511 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001512#if THROW_ON_BAD_ID
1513 if (newBlock == BAD_INDEX) {
1514 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1515 return JNI_FALSE;
1516 }
1517#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 if (newBlock >= 0) block = newBlock;
1519 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 // Deal with the special @null value -- it turns back to TYPE_NULL.
1522 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1523 value.dataType = Res_value::TYPE_NULL;
1524 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 // Write the final value back to Java.
1529 dest[STYLE_TYPE] = value.dataType;
1530 dest[STYLE_DATA] = value.data;
1531 dest[STYLE_ASSET_COOKIE] =
Ashok Bhat896043d2014-01-17 16:02:38 +00001532 block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 dest[STYLE_RESOURCE_ID] = resid;
1534 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001535 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1538 indicesIdx++;
1539 indices[indicesIdx] = ii;
1540 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 dest += STYLE_NUM_ENTRIES;
1543 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 if (indices != NULL) {
1548 indices[0] = indicesIdx;
1549 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1550 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1553 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 return JNI_TRUE;
1556}
1557
1558static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1559 jint id)
1560{
1561 AssetManager* am = assetManagerForJavaObject(env, clazz);
1562 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001563 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
1565 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 res.lock();
1568 const ResTable::bag_entry* defStyleEnt = NULL;
1569 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1570 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001571
Ashok Bhat896043d2014-01-17 16:02:38 +00001572 return static_cast<jint>(bagOff);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573}
1574
1575static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1576 jint id,
1577 jintArray outValues)
1578{
1579 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001580 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 return JNI_FALSE;
1582 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 AssetManager* am = assetManagerForJavaObject(env, clazz);
1585 if (am == NULL) {
1586 return JNI_FALSE;
1587 }
1588 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001589 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 Res_value value;
1591 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1596 jint* dest = baseDest;
1597 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001598 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 return JNI_FALSE;
1600 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 // Now lock down the resource object and start pulling stuff from it.
1603 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 const ResTable::bag_entry* arrayEnt = NULL;
1606 uint32_t arrayTypeSetFlags = 0;
1607 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1608 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1609 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 int i = 0;
1612 uint32_t typeSetFlags;
1613 while (i < NV && arrayEnt < endArrayEnt) {
1614 block = arrayEnt->stringBlock;
1615 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001616 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 uint32_t resid = 0;
1620 if (value.dataType != Res_value::TYPE_NULL) {
1621 // Take care of resolving the found resource to its final value.
1622 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001623 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1624 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001625#if THROW_ON_BAD_ID
1626 if (newBlock == BAD_INDEX) {
1627 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1628 return JNI_FALSE;
1629 }
1630#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 if (newBlock >= 0) block = newBlock;
1632 }
1633
1634 // Deal with the special @null value -- it turns back to TYPE_NULL.
1635 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1636 value.dataType = Res_value::TYPE_NULL;
1637 }
1638
1639 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1640
1641 // Write the final value back to Java.
1642 dest[STYLE_TYPE] = value.dataType;
1643 dest[STYLE_DATA] = value.data;
Ashok Bhat896043d2014-01-17 16:02:38 +00001644 dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 dest[STYLE_RESOURCE_ID] = resid;
1646 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001647 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 dest += STYLE_NUM_ENTRIES;
1649 i+= STYLE_NUM_ENTRIES;
1650 arrayEnt++;
1651 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 return i;
1660}
1661
Ashok Bhat896043d2014-01-17 16:02:38 +00001662static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 jint cookie,
1664 jstring fileName)
1665{
1666 AssetManager* am = assetManagerForJavaObject(env, clazz);
1667 if (am == NULL) {
1668 return 0;
1669 }
1670
Steve Block71f2cf12011-10-20 11:56:00 +01001671 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672
Elliott Hughes69a017b2011-04-08 14:10:28 -07001673 ScopedUtfChars fileName8(env, fileName);
1674 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 return 0;
1676 }
1677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +00001679 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_BUFFER)
Elliott Hughes69a017b2011-04-08 14:10:28 -07001680 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681
1682 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001683 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 return 0;
1685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686
1687 ResXMLTree* block = new ResXMLTree();
1688 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1689 a->close();
1690 delete a;
1691
1692 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001693 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 return 0;
1695 }
1696
Ashok Bhat896043d2014-01-17 16:02:38 +00001697 return reinterpret_cast<jlong>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698}
1699
1700static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1701 jint arrayResId)
1702{
1703 AssetManager* am = assetManagerForJavaObject(env, clazz);
1704 if (am == NULL) {
1705 return NULL;
1706 }
1707 const ResTable& res(am->getResources());
1708
1709 const ResTable::bag_entry* startOfBag;
1710 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1711 if (N < 0) {
1712 return NULL;
1713 }
1714
1715 jintArray array = env->NewIntArray(N * 2);
1716 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 res.unlockBag(startOfBag);
1718 return NULL;
1719 }
1720
1721 Res_value value;
1722 const ResTable::bag_entry* bag = startOfBag;
1723 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1724 jint stringIndex = -1;
1725 jint stringBlock = 0;
1726 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 // Take care of resolving the found resource to its final value.
1729 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1730 if (value.dataType == Res_value::TYPE_STRING) {
1731 stringIndex = value.data;
1732 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001733
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001734#if THROW_ON_BAD_ID
1735 if (stringBlock == BAD_INDEX) {
1736 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1737 return array;
1738 }
1739#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 //todo: It might be faster to allocate a C array to contain
1742 // the blocknums and indices, put them in there and then
1743 // do just one SetIntArrayRegion()
1744 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1745 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1746 j = j + 2;
1747 }
1748 res.unlockBag(startOfBag);
1749 return array;
1750}
1751
1752static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1753 jint arrayResId)
1754{
1755 AssetManager* am = assetManagerForJavaObject(env, clazz);
1756 if (am == NULL) {
1757 return NULL;
1758 }
1759 const ResTable& res(am->getResources());
1760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 const ResTable::bag_entry* startOfBag;
1762 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1763 if (N < 0) {
1764 return NULL;
1765 }
1766
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001767 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001768 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 res.unlockBag(startOfBag);
1770 return NULL;
1771 }
1772
1773 Res_value value;
1774 const ResTable::bag_entry* bag = startOfBag;
1775 size_t strLen = 0;
1776 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1777 value = bag->map.value;
1778 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 // Take care of resolving the found resource to its final value.
1781 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001782#if THROW_ON_BAD_ID
1783 if (block == BAD_INDEX) {
1784 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1785 return array;
1786 }
1787#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001789 const ResStringPool* pool = res.getTableStringBlock(block);
1790 const char* str8 = pool->string8At(value.data, &strLen);
1791 if (str8 != NULL) {
1792 str = env->NewStringUTF(str8);
1793 } else {
1794 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1795 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001796 }
1797
1798 // If one of our NewString{UTF} calls failed due to memory, an
1799 // exception will be pending.
1800 if (env->ExceptionCheck()) {
1801 res.unlockBag(startOfBag);
1802 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
Kenny Root780d2a12010-02-22 22:36:26 -08001804
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001805 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001806
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001807 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1808 // If we have a large amount of strings in our array, we might
1809 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001810 env->DeleteLocalRef(str);
1811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813 res.unlockBag(startOfBag);
1814 return array;
1815}
1816
1817static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1818 jint arrayResId)
1819{
1820 AssetManager* am = assetManagerForJavaObject(env, clazz);
1821 if (am == NULL) {
1822 return NULL;
1823 }
1824 const ResTable& res(am->getResources());
1825
1826 const ResTable::bag_entry* startOfBag;
1827 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1828 if (N < 0) {
1829 return NULL;
1830 }
1831
1832 jintArray array = env->NewIntArray(N);
1833 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 res.unlockBag(startOfBag);
1835 return NULL;
1836 }
1837
1838 Res_value value;
1839 const ResTable::bag_entry* bag = startOfBag;
1840 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1841 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 // Take care of resolving the found resource to its final value.
1844 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001845#if THROW_ON_BAD_ID
1846 if (block == BAD_INDEX) {
1847 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1848 return array;
1849 }
1850#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 if (value.dataType >= Res_value::TYPE_FIRST_INT
1852 && value.dataType <= Res_value::TYPE_LAST_INT) {
1853 int intVal = value.data;
1854 env->SetIntArrayRegion(array, i, 1, &intVal);
1855 }
1856 }
1857 res.unlockBag(startOfBag);
1858 return array;
1859}
1860
Mårten Kongstad48d22322014-01-31 14:43:27 +01001861static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862{
Mårten Kongstad48d22322014-01-31 14:43:27 +01001863 if (isSystem) {
1864 verifySystemIdmaps();
1865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 AssetManager* am = new AssetManager();
1867 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001868 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 return;
1870 }
1871
1872 am->addDefaultAssets();
1873
Steve Block71f2cf12011-10-20 11:56:00 +01001874 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
Ashok Bhat896043d2014-01-17 16:02:38 +00001875 env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876}
1877
1878static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1879{
1880 AssetManager* am = (AssetManager*)
Ashok Bhat896043d2014-01-17 16:02:38 +00001881 (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001882 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 if (am != NULL) {
1884 delete am;
Ashok Bhat896043d2014-01-17 16:02:38 +00001885 env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 }
1887}
1888
1889static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1890{
1891 return Asset::getGlobalCount();
1892}
1893
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001894static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1895{
1896 String8 alloc = Asset::getAssetAllocations();
1897 if (alloc.length() <= 0) {
1898 return NULL;
1899 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001900
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001901 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001902 return str;
1903}
1904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1906{
1907 return AssetManager::getGlobalCount();
1908}
1909
1910// ----------------------------------------------------------------------------
1911
1912/*
1913 * JNI registration.
1914 */
1915static JNINativeMethod gAssetManagerMethods[] = {
1916 /* name, signature, funcPtr */
1917
1918 // Basic asset stuff.
Ashok Bhat896043d2014-01-17 16:02:38 +00001919 { "openAsset", "(Ljava/lang/String;I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 (void*) android_content_AssetManager_openAsset },
1921 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1922 (void*) android_content_AssetManager_openAssetFd },
Ashok Bhat896043d2014-01-17 16:02:38 +00001923 { "openNonAssetNative", "(ILjava/lang/String;I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 (void*) android_content_AssetManager_openNonAssetNative },
1925 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1926 (void*) android_content_AssetManager_openNonAssetFdNative },
1927 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1928 (void*) android_content_AssetManager_list },
Ashok Bhat896043d2014-01-17 16:02:38 +00001929 { "destroyAsset", "(J)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 (void*) android_content_AssetManager_destroyAsset },
Ashok Bhat896043d2014-01-17 16:02:38 +00001931 { "readAssetChar", "(J)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 (void*) android_content_AssetManager_readAssetChar },
Ashok Bhat896043d2014-01-17 16:02:38 +00001933 { "readAsset", "(J[BII)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 (void*) android_content_AssetManager_readAsset },
Ashok Bhat896043d2014-01-17 16:02:38 +00001935 { "seekAsset", "(JJI)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 (void*) android_content_AssetManager_seekAsset },
Ashok Bhat896043d2014-01-17 16:02:38 +00001937 { "getAssetLength", "(J)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 (void*) android_content_AssetManager_getAssetLength },
Ashok Bhat896043d2014-01-17 16:02:38 +00001939 { "getAssetRemainingLength", "(J)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 (void*) android_content_AssetManager_getAssetRemainingLength },
Dianne Hackbornf7be4802013-04-12 14:52:58 -07001941 { "addAssetPathNative", "(Ljava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 (void*) android_content_AssetManager_addAssetPath },
Mårten Kongstad48d22322014-01-31 14:43:27 +01001943 { "addOverlayPath", "(Ljava/lang/String;)I",
1944 (void*) android_content_AssetManager_addOverlayPath },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 { "isUpToDate", "()Z",
1946 (void*) android_content_AssetManager_isUpToDate },
1947
1948 // Resources.
1949 { "setLocale", "(Ljava/lang/String;)V",
1950 (void*) android_content_AssetManager_setLocale },
1951 { "getLocales", "()[Ljava/lang/String;",
1952 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001953 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 (void*) android_content_AssetManager_setConfiguration },
1955 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1956 (void*) android_content_AssetManager_getResourceIdentifier },
1957 { "getResourceName","(I)Ljava/lang/String;",
1958 (void*) android_content_AssetManager_getResourceName },
1959 { "getResourcePackageName","(I)Ljava/lang/String;",
1960 (void*) android_content_AssetManager_getResourcePackageName },
1961 { "getResourceTypeName","(I)Ljava/lang/String;",
1962 (void*) android_content_AssetManager_getResourceTypeName },
1963 { "getResourceEntryName","(I)Ljava/lang/String;",
1964 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001965 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 (void*) android_content_AssetManager_loadResourceValue },
1967 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1968 (void*) android_content_AssetManager_loadResourceBagValue },
1969 { "getStringBlockCount","()I",
1970 (void*) android_content_AssetManager_getStringBlockCount },
Ashok Bhat896043d2014-01-17 16:02:38 +00001971 { "getNativeStringBlock","(I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 (void*) android_content_AssetManager_getNativeStringBlock },
1973 { "getCookieName","(I)Ljava/lang/String;",
1974 (void*) android_content_AssetManager_getCookieName },
1975
1976 // Themes.
Ashok Bhat896043d2014-01-17 16:02:38 +00001977 { "newTheme", "()J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 (void*) android_content_AssetManager_newTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00001979 { "deleteTheme", "(J)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 (void*) android_content_AssetManager_deleteTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00001981 { "applyThemeStyle", "(JIZ)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 (void*) android_content_AssetManager_applyThemeStyle },
Ashok Bhat896043d2014-01-17 16:02:38 +00001983 { "copyTheme", "(JJ)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 (void*) android_content_AssetManager_copyTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00001985 { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 (void*) android_content_AssetManager_loadThemeAttributeValue },
Ashok Bhat896043d2014-01-17 16:02:38 +00001987 { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 (void*) android_content_AssetManager_dumpTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00001989 { "applyStyle","(JIIJ[I[I[I)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 (void*) android_content_AssetManager_applyStyle },
Ashok Bhat896043d2014-01-17 16:02:38 +00001991 { "retrieveAttributes","(J[I[I[I)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 (void*) android_content_AssetManager_retrieveAttributes },
1993 { "getArraySize","(I)I",
1994 (void*) android_content_AssetManager_getArraySize },
1995 { "retrieveArray","(I[I)I",
1996 (void*) android_content_AssetManager_retrieveArray },
1997
1998 // XML files.
Ashok Bhat896043d2014-01-17 16:02:38 +00001999 { "openXmlAssetNative", "(ILjava/lang/String;)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 (void*) android_content_AssetManager_openXmlAssetNative },
2001
2002 // Arrays.
2003 { "getArrayStringResource","(I)[Ljava/lang/String;",
2004 (void*) android_content_AssetManager_getArrayStringResource },
2005 { "getArrayStringInfo","(I)[I",
2006 (void*) android_content_AssetManager_getArrayStringInfo },
2007 { "getArrayIntResource","(I)[I",
2008 (void*) android_content_AssetManager_getArrayIntResource },
2009
2010 // Bookkeeping.
Mårten Kongstad48d22322014-01-31 14:43:27 +01002011 { "init", "(Z)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 (void*) android_content_AssetManager_init },
2013 { "destroy", "()V",
2014 (void*) android_content_AssetManager_destroy },
2015 { "getGlobalAssetCount", "()I",
2016 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07002017 { "getAssetAllocations", "()Ljava/lang/String;",
2018 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 { "getGlobalAssetManagerCount", "()I",
2020 (void*) android_content_AssetManager_getGlobalAssetCount },
2021};
2022
2023int register_android_content_AssetManager(JNIEnv* env)
2024{
2025 jclass typedValue = env->FindClass("android/util/TypedValue");
2026 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
2027 gTypedValueOffsets.mType
2028 = env->GetFieldID(typedValue, "type", "I");
2029 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
2030 gTypedValueOffsets.mData
2031 = env->GetFieldID(typedValue, "data", "I");
2032 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
2033 gTypedValueOffsets.mString
2034 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
2035 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
2036 gTypedValueOffsets.mAssetCookie
2037 = env->GetFieldID(typedValue, "assetCookie", "I");
2038 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
2039 gTypedValueOffsets.mResourceId
2040 = env->GetFieldID(typedValue, "resourceId", "I");
2041 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
2042 gTypedValueOffsets.mChangingConfigurations
2043 = env->GetFieldID(typedValue, "changingConfigurations", "I");
2044 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
2045 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
2046 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
2047
2048 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
2049 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
2050 gAssetFileDescriptorOffsets.mFd
2051 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
2052 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
2053 gAssetFileDescriptorOffsets.mStartOffset
2054 = env->GetFieldID(assetFd, "mStartOffset", "J");
2055 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
2056 gAssetFileDescriptorOffsets.mLength
2057 = env->GetFieldID(assetFd, "mLength", "J");
2058 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
2059
2060 jclass assetManager = env->FindClass("android/content/res/AssetManager");
2061 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
2062 gAssetManagerOffsets.mObject
Ashok Bhat896043d2014-01-17 16:02:38 +00002063 = env->GetFieldID(assetManager, "mObject", "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
2065
Carl Shapiroc1318ba2011-03-03 14:22:28 -08002066 jclass stringClass = env->FindClass("java/lang/String");
2067 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
2068 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01002069 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 -08002070
2071 return AndroidRuntime::registerNativeMethods(env,
2072 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
2073}
2074
2075}; // namespace android