blob: 55b7e7ec8325a328c43d5cbd891a98723f5fabc7 [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
20#include <android_runtime/android_util_AssetManager.h>
21
Dan Albert46d84442014-11-18 16:07:51 -080022#include <inttypes.h>
23#include <linux/capability.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024#include <stdio.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010025#include <sys/types.h>
26#include <sys/wait.h>
Mårten Kongstad83ab0d72015-03-20 12:57:36 +010027#include <sys/stat.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010028
Dan Albert46d84442014-11-18 16:07:51 -080029#include <private/android_filesystem_config.h> // for AID_SYSTEM
30
Dan Albert3a091b72014-11-20 15:41:25 -080031#include "androidfw/Asset.h"
32#include "androidfw/AssetManager.h"
33#include "androidfw/AttributeFinder.h"
34#include "androidfw/ResourceTypes.h"
35#include "android_runtime/AndroidRuntime.h"
36#include "android_util_Binder.h"
37#include "core_jni_helpers.h"
38#include "jni.h"
Dan Albert46d84442014-11-18 16:07:51 -080039#include "JNIHelp.h"
40#include "ScopedStringChars.h"
41#include "ScopedUtfChars.h"
Dan Albert46d84442014-11-18 16:07:51 -080042#include "utils/Log.h"
43#include "utils/misc.h"
44
Mårten Kongstad48d22322014-01-31 14:43:27 +010045extern "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
Andreas Gampe0f0b4912014-11-12 08:03:48 -080051static const bool kThrowOnBadId = false;
52static const bool kDebugStyles = false;
53
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054// ----------------------------------------------------------------------------
55
56static struct typedvalue_offsets_t
57{
58 jfieldID mType;
59 jfieldID mData;
60 jfieldID mString;
61 jfieldID mAssetCookie;
62 jfieldID mResourceId;
63 jfieldID mChangingConfigurations;
64 jfieldID mDensity;
65} gTypedValueOffsets;
66
67static struct assetfiledescriptor_offsets_t
68{
69 jfieldID mFd;
70 jfieldID mStartOffset;
71 jfieldID mLength;
72} gAssetFileDescriptorOffsets;
73
74static struct assetmanager_offsets_t
75{
76 jfieldID mObject;
77} gAssetManagerOffsets;
78
Adam Lesinskide898ff2014-01-29 18:20:45 -080079static struct sparsearray_offsets_t
80{
81 jclass classObject;
82 jmethodID constructor;
83 jmethodID put;
84} gSparseArrayOffsets;
85
Filip Gruszczynski23493322015-07-29 17:02:59 -070086static struct configuration_offsets_t
87{
88 jclass classObject;
89 jmethodID constructor;
90 jfieldID mSmallestScreenWidthDpOffset;
91 jfieldID mScreenWidthDpOffset;
92 jfieldID mScreenHeightDpOffset;
93} gConfigurationOffsets;
94
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095jclass g_stringClass = NULL;
96
97// ----------------------------------------------------------------------------
98
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -0700100 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 STYLE_TYPE = 0,
102 STYLE_DATA = 1,
103 STYLE_ASSET_COOKIE = 2,
104 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -0700105 STYLE_CHANGING_CONFIGURATIONS = 4,
106 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107};
108
109static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
110 const Res_value& value, uint32_t ref, ssize_t block,
111 uint32_t typeSpecFlags, ResTable_config* config = NULL);
112
113jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
114 const Res_value& value, uint32_t ref, ssize_t block,
115 uint32_t typeSpecFlags, ResTable_config* config)
116{
117 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
118 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
Ashok Bhat896043d2014-01-17 16:02:38 +0000119 static_cast<jint>(table->getTableCookie(block)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
121 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
122 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
123 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
124 typeSpecFlags);
125 if (config != NULL) {
126 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
127 }
128 return block;
129}
130
Mårten Kongstad48d22322014-01-31 14:43:27 +0100131// This is called by zygote (running as user root) as part of preloadResources.
132static void verifySystemIdmaps()
133{
134 pid_t pid;
135 char system_id[10];
136
137 snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
138
139 switch (pid = fork()) {
140 case -1:
141 ALOGE("failed to fork for idmap: %s", strerror(errno));
142 break;
143 case 0: // child
144 {
145 struct __user_cap_header_struct capheader;
146 struct __user_cap_data_struct capdata;
147
148 memset(&capheader, 0, sizeof(capheader));
149 memset(&capdata, 0, sizeof(capdata));
150
151 capheader.version = _LINUX_CAPABILITY_VERSION;
152 capheader.pid = 0;
153
154 if (capget(&capheader, &capdata) != 0) {
155 ALOGE("capget: %s\n", strerror(errno));
156 exit(1);
157 }
158
159 capdata.effective = capdata.permitted;
160 if (capset(&capheader, &capdata) != 0) {
161 ALOGE("capset: %s\n", strerror(errno));
162 exit(1);
163 }
164
165 if (setgid(AID_SYSTEM) != 0) {
166 ALOGE("setgid: %s\n", strerror(errno));
167 exit(1);
168 }
169
170 if (setuid(AID_SYSTEM) != 0) {
171 ALOGE("setuid: %s\n", strerror(errno));
172 exit(1);
173 }
174
Mårten Kongstad83ab0d72015-03-20 12:57:36 +0100175 // Generic idmap parameters
176 const char* argv[7];
177 int argc = 0;
178 struct stat st;
179
180 memset(argv, NULL, sizeof(argv));
181 argv[argc++] = AssetManager::IDMAP_BIN;
182 argv[argc++] = "--scan";
183 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
184 argv[argc++] = AssetManager::TARGET_APK_PATH;
185 argv[argc++] = AssetManager::IDMAP_DIR;
186
187 // Directories to scan for overlays
188 // /vendor/overlay
189 if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
190 argv[argc++] = AssetManager::OVERLAY_DIR;
191 }
192
193 // Finally, invoke idmap (if any overlay directory exists)
194 if (argc > 5) {
195 execv(AssetManager::IDMAP_BIN, (char* const*)argv);
196 ALOGE("failed to execl for idmap: %s", strerror(errno));
197 exit(1); // should never get here
198 } else {
199 exit(0);
200 }
Mårten Kongstad48d22322014-01-31 14:43:27 +0100201 }
202 break;
203 default: // parent
204 waitpid(pid, NULL, 0);
205 break;
206 }
207}
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209// ----------------------------------------------------------------------------
210
211// this guy is exported to other jni routines
212AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
213{
Ashok Bhat896043d2014-01-17 16:02:38 +0000214 jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
215 AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 if (am != NULL) {
217 return am;
218 }
219 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
220 return NULL;
221}
222
Ashok Bhat896043d2014-01-17 16:02:38 +0000223static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 jstring fileName, jint mode)
225{
226 AssetManager* am = assetManagerForJavaObject(env, clazz);
227 if (am == NULL) {
228 return 0;
229 }
230
Steve Block71f2cf12011-10-20 11:56:00 +0100231 ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Elliott Hughes69a017b2011-04-08 14:10:28 -0700233 ScopedUtfChars fileName8(env, fileName);
234 if (fileName8.c_str() == NULL) {
Ashok Bhat896043d2014-01-17 16:02:38 +0000235 jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 return -1;
237 }
238
239 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
240 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700241 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 return -1;
243 }
244
Elliott Hughes69a017b2011-04-08 14:10:28 -0700245 Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246
247 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700248 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 return -1;
250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
252 //printf("Created Asset Stream: %p\n", a);
253
Ashok Bhat896043d2014-01-17 16:02:38 +0000254 return reinterpret_cast<jlong>(a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255}
256
257static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
258{
Kenny Rootddb76c42010-11-24 12:56:06 -0800259 off64_t startOffset, length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 int fd = a->openFileDescriptor(&startOffset, &length);
261 delete a;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 if (fd < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700264 jniThrowException(env, "java/io/FileNotFoundException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 "This file can not be opened as a file descriptor; it is probably compressed");
266 return NULL;
267 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
270 if (offsets == NULL) {
271 close(fd);
272 return NULL;
273 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 offsets[0] = startOffset;
276 offsets[1] = length;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700279
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700280 jobject fileDesc = jniCreateFileDescriptor(env, fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 if (fileDesc == NULL) {
282 close(fd);
283 return NULL;
284 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 return newParcelFileDescriptor(env, fileDesc);
287}
288
289static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
290 jstring fileName, jlongArray outOffsets)
291{
292 AssetManager* am = assetManagerForJavaObject(env, clazz);
293 if (am == NULL) {
294 return NULL;
295 }
296
Steve Block71f2cf12011-10-20 11:56:00 +0100297 ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298
Elliott Hughes69a017b2011-04-08 14:10:28 -0700299 ScopedUtfChars fileName8(env, fileName);
300 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 return NULL;
302 }
303
Elliott Hughes69a017b2011-04-08 14:10:28 -0700304 Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305
306 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700307 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 return NULL;
309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310
311 //printf("Created Asset Stream: %p\n", a);
312
313 return returnParcelFileDescriptor(env, a, outOffsets);
314}
315
Ashok Bhat896043d2014-01-17 16:02:38 +0000316static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 jint cookie,
318 jstring fileName,
319 jint mode)
320{
321 AssetManager* am = assetManagerForJavaObject(env, clazz);
322 if (am == NULL) {
323 return 0;
324 }
325
Steve Block71f2cf12011-10-20 11:56:00 +0100326 ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327
Elliott Hughes69a017b2011-04-08 14:10:28 -0700328 ScopedUtfChars fileName8(env, fileName);
329 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 return -1;
331 }
332
333 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
334 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700335 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 return -1;
337 }
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000340 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
341 (Asset::AccessMode)mode)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700342 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343
344 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700345 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return -1;
347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348
349 //printf("Created Asset Stream: %p\n", a);
350
Ashok Bhat896043d2014-01-17 16:02:38 +0000351 return reinterpret_cast<jlong>(a);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352}
353
354static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
355 jint cookie,
356 jstring fileName,
357 jlongArray outOffsets)
358{
359 AssetManager* am = assetManagerForJavaObject(env, clazz);
360 if (am == NULL) {
361 return NULL;
362 }
363
Steve Block71f2cf12011-10-20 11:56:00 +0100364 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365
Elliott Hughes69a017b2011-04-08 14:10:28 -0700366 ScopedUtfChars fileName8(env, fileName);
367 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 return NULL;
369 }
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 Asset* a = cookie
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000372 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
Elliott Hughes69a017b2011-04-08 14:10:28 -0700373 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
375 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700376 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 return NULL;
378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379
380 //printf("Created Asset Stream: %p\n", a);
381
382 return returnParcelFileDescriptor(env, a, outOffsets);
383}
384
385static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
386 jstring fileName)
387{
388 AssetManager* am = assetManagerForJavaObject(env, clazz);
389 if (am == NULL) {
390 return NULL;
391 }
392
Elliott Hughes69a017b2011-04-08 14:10:28 -0700393 ScopedUtfChars fileName8(env, fileName);
394 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 return NULL;
396 }
397
Elliott Hughes69a017b2011-04-08 14:10:28 -0700398 AssetDir* dir = am->openDir(fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399
400 if (dir == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700401 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 return NULL;
403 }
404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 size_t N = dir->getFileCount();
406
407 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +0100408 g_stringClass, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 delete dir;
411 return NULL;
412 }
413
414 for (size_t i=0; i<N; i++) {
415 const String8& name = dir->getFileName(i);
416 jstring str = env->NewStringUTF(name.string());
417 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 delete dir;
419 return NULL;
420 }
421 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700422 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 }
424
425 delete dir;
426
427 return array;
428}
429
430static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000431 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432{
Ashok Bhat896043d2014-01-17 16:02:38 +0000433 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434
435 //printf("Destroying Asset Stream: %p\n", a);
436
437 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700438 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 return;
440 }
441
442 delete a;
443}
444
445static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000446 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447{
Ashok Bhat896043d2014-01-17 16:02:38 +0000448 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449
450 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700451 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 return -1;
453 }
454
455 uint8_t b;
456 ssize_t res = a->read(&b, 1);
457 return res == 1 ? b : -1;
458}
459
460static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000461 jlong assetHandle, jbyteArray bArray,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 jint off, jint len)
463{
Ashok Bhat896043d2014-01-17 16:02:38 +0000464 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465
466 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700467 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 return -1;
469 }
470
471 if (len == 0) {
472 return 0;
473 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 jsize bLen = env->GetArrayLength(bArray);
476 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700477 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 return -1;
479 }
480
481 jbyte* b = env->GetByteArrayElements(bArray, NULL);
482 ssize_t res = a->read(b+off, len);
483 env->ReleaseByteArrayElements(bArray, b, 0);
484
Ashok Bhat896043d2014-01-17 16:02:38 +0000485 if (res > 0) return static_cast<jint>(res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486
487 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700488 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 return -1;
491}
492
493static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000494 jlong assetHandle,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 jlong offset, jint whence)
496{
Ashok Bhat896043d2014-01-17 16:02:38 +0000497 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498
499 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700500 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 return -1;
502 }
503
504 return a->seek(
505 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
506}
507
508static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000509 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510{
Ashok Bhat896043d2014-01-17 16:02:38 +0000511 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512
513 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700514 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 return -1;
516 }
517
518 return a->getLength();
519}
520
521static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +0000522 jlong assetHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523{
Ashok Bhat896043d2014-01-17 16:02:38 +0000524 Asset* a = reinterpret_cast<Asset*>(assetHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525
526 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700527 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 return -1;
529 }
530
531 return a->getRemainingLength();
532}
533
534static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
Tao Baia6d7e3f2015-09-01 18:49:54 -0700535 jstring path, jboolean appAsLib)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700537 ScopedUtfChars path8(env, path);
538 if (path8.c_str() == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800539 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 }
541
542 AssetManager* am = assetManagerForJavaObject(env, clazz);
543 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800544 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 }
546
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000547 int32_t cookie;
Tao Baia6d7e3f2015-09-01 18:49:54 -0700548 bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549
Narayan Kamath745d4ef2014-01-27 11:17:22 +0000550 return (res) ? static_cast<jint>(cookie) : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551}
552
Mårten Kongstad48d22322014-01-31 14:43:27 +0100553static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
554 jstring idmapPath)
555{
556 ScopedUtfChars idmapPath8(env, idmapPath);
557 if (idmapPath8.c_str() == NULL) {
558 return 0;
559 }
560
561 AssetManager* am = assetManagerForJavaObject(env, clazz);
562 if (am == NULL) {
563 return 0;
564 }
565
566 int32_t cookie;
567 bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
568
569 return (res) ? (jint)cookie : 0;
570}
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
573{
574 AssetManager* am = assetManagerForJavaObject(env, clazz);
575 if (am == NULL) {
576 return JNI_TRUE;
577 }
578 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
579}
580
581static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
582 jstring locale)
583{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700584 ScopedUtfChars locale8(env, locale);
585 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return;
587 }
588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 AssetManager* am = assetManagerForJavaObject(env, clazz);
590 if (am == NULL) {
591 return;
592 }
593
Elliott Hughes69a017b2011-04-08 14:10:28 -0700594 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595}
596
597static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
598{
599 Vector<String8> locales;
600
601 AssetManager* am = assetManagerForJavaObject(env, clazz);
602 if (am == NULL) {
603 return NULL;
604 }
605
606 am->getLocales(&locales);
607
608 const int N = locales.size();
609
610 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
611 if (result == NULL) {
612 return NULL;
613 }
614
615 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700616 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700617 if (str == NULL) {
618 return NULL;
619 }
620 env->SetObjectArrayElement(result, i, str);
621 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
623
624 return result;
625}
626
Filip Gruszczynski23493322015-07-29 17:02:59 -0700627static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
628 jobject result = env->NewObject(gConfigurationOffsets.classObject,
629 gConfigurationOffsets.constructor);
630 if (result == NULL) {
631 return NULL;
632 }
633
634 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
635 config.smallestScreenWidthDp);
636 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
637 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
638
639 return result;
640}
641
642static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
643 const Vector<ResTable_config>& configs) {
644 const int N = configs.size();
645 jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
646 if (result == NULL) {
647 return NULL;
648 }
649
650 for (int i=0; i<N; i++) {
651 jobject config = constructConfigurationObject(env, configs[i]);
652 if (config == NULL) {
653 env->DeleteLocalRef(result);
654 return NULL;
655 }
656
657 env->SetObjectArrayElement(result, i, config);
658 env->DeleteLocalRef(config);
659 }
660
661 return result;
662}
663
664static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
665 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 if (am == NULL) {
667 return NULL;
668 }
669
670 const ResTable& res(am->getResources());
671 Vector<ResTable_config> configs;
672 res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
673
674 return getSizeConfigurationsInternal(env, configs);
675}
676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
678 jint mcc, jint mnc,
679 jstring locale, jint orientation,
680 jint touchscreen, jint density,
681 jint keyboard, jint keyboardHidden,
682 jint navigation,
683 jint screenWidth, jint screenHeight,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700684 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700685 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100686 jint screenLayout, jint uiMode,
687 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688{
689 AssetManager* am = assetManagerForJavaObject(env, clazz);
690 if (am == NULL) {
691 return;
692 }
693
694 ResTable_config config;
695 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700698
Adam Lesinski2738c962015-05-14 14:25:36 -0700699 // Constants duplicated from Java class android.content.res.Configuration.
700 static const jint kScreenLayoutRoundMask = 0x300;
701 static const jint kScreenLayoutRoundShift = 8;
702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 config.mcc = (uint16_t)mcc;
704 config.mnc = (uint16_t)mnc;
705 config.orientation = (uint8_t)orientation;
706 config.touchscreen = (uint8_t)touchscreen;
707 config.density = (uint16_t)density;
708 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700709 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 config.navigation = (uint8_t)navigation;
711 config.screenWidth = (uint16_t)screenWidth;
712 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700713 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700714 config.screenWidthDp = (uint16_t)screenWidthDp;
715 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700716 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100717 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 config.sdkVersion = (uint16_t)sdkVersion;
719 config.minorVersion = 0;
Adam Lesinski2738c962015-05-14 14:25:36 -0700720
721 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
722 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
723 // into screenLayout2.
724 config.screenLayout2 =
725 (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
730}
731
732static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
733 jstring name,
734 jstring defType,
735 jstring defPackage)
736{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700737 ScopedStringChars name16(env, name);
738 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 return 0;
740 }
741
742 AssetManager* am = assetManagerForJavaObject(env, clazz);
743 if (am == NULL) {
744 return 0;
745 }
746
Dan Albert66987492014-11-20 11:41:21 -0800747 const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
748 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
749 : NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 jsize defTypeLen = defType
751 ? env->GetStringLength(defType) : 0;
Dan Albert66987492014-11-20 11:41:21 -0800752 const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
753 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
754 NULL))
755 : NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 jsize defPackageLen = defPackage
757 ? env->GetStringLength(defPackage) : 0;
758
759 jint ident = am->getResources().identifierForName(
Dan Albert66987492014-11-20 11:41:21 -0800760 reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
761 defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762
763 if (defPackage16) {
Dan Albert66987492014-11-20 11:41:21 -0800764 env->ReleaseStringChars(defPackage,
765 reinterpret_cast<const jchar*>(defPackage16));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 if (defType16) {
Dan Albert66987492014-11-20 11:41:21 -0800768 env->ReleaseStringChars(defType,
769 reinterpret_cast<const jchar*>(defType16));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771
772 return ident;
773}
774
775static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
776 jint resid)
777{
778 AssetManager* am = assetManagerForJavaObject(env, clazz);
779 if (am == NULL) {
780 return NULL;
781 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700784 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 return NULL;
786 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 String16 str;
789 if (name.package != NULL) {
790 str.setTo(name.package, name.packageLen);
791 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700792 if (name.type8 != NULL || name.type != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 if (str.size() > 0) {
794 char16_t div = ':';
795 str.append(&div, 1);
796 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700797 if (name.type8 != NULL) {
798 str.append(String16(name.type8, name.typeLen));
799 } else {
800 str.append(name.type, name.typeLen);
801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700803 if (name.name8 != NULL || name.name != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 if (str.size() > 0) {
805 char16_t div = '/';
806 str.append(&div, 1);
807 }
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700808 if (name.name8 != NULL) {
809 str.append(String16(name.name8, name.nameLen));
810 } else {
811 str.append(name.name, name.nameLen);
812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 return env->NewString((const jchar*)str.string(), str.size());
816}
817
818static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
819 jint resid)
820{
821 AssetManager* am = assetManagerForJavaObject(env, clazz);
822 if (am == NULL) {
823 return NULL;
824 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700827 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 return NULL;
829 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 if (name.package != NULL) {
832 return env->NewString((const jchar*)name.package, name.packageLen);
833 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 return NULL;
836}
837
838static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
839 jint resid)
840{
841 AssetManager* am = assetManagerForJavaObject(env, clazz);
842 if (am == NULL) {
843 return NULL;
844 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700847 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 return NULL;
849 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700850
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700851 if (name.type8 != NULL) {
852 return env->NewStringUTF(name.type8);
853 }
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 if (name.type != NULL) {
856 return env->NewString((const jchar*)name.type, name.typeLen);
857 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 return NULL;
860}
861
862static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
863 jint resid)
864{
865 AssetManager* am = assetManagerForJavaObject(env, clazz);
866 if (am == NULL) {
867 return NULL;
868 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 ResTable::resource_name name;
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700871 if (!am->getResources().getResourceName(resid, true, &name)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 return NULL;
873 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700874
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700875 if (name.name8 != NULL) {
876 return env->NewStringUTF(name.name8);
877 }
878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 if (name.name != NULL) {
880 return env->NewString((const jchar*)name.name, name.nameLen);
881 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return NULL;
884}
885
886static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
887 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700888 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 jobject outValue,
890 jboolean resolve)
891{
Dianne Hackborn1f7d3072013-02-11 17:03:32 -0800892 if (outValue == NULL) {
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800893 jniThrowNullPointerException(env, "outValue");
Dianne Hackbornd45c68d2013-07-31 12:14:24 -0700894 return 0;
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800895 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 AssetManager* am = assetManagerForJavaObject(env, clazz);
897 if (am == NULL) {
898 return 0;
899 }
900 const ResTable& res(am->getResources());
901
902 Res_value value;
903 ResTable_config config;
904 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700905 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800906 if (kThrowOnBadId) {
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800907 if (block == BAD_INDEX) {
908 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
909 return 0;
910 }
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800911 }
912 uint32_t ref = ident;
913 if (resolve) {
914 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
915 if (kThrowOnBadId) {
916 if (block == BAD_INDEX) {
917 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
918 return 0;
919 }
920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000922 if (block >= 0) {
923 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
924 }
925
926 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927}
928
929static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
930 jint ident, jint bagEntryId,
931 jobject outValue, jboolean resolve)
932{
933 AssetManager* am = assetManagerForJavaObject(env, clazz);
934 if (am == NULL) {
935 return 0;
936 }
937 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 // Now lock down the resource object and start pulling stuff from it.
940 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 ssize_t block = -1;
943 Res_value value;
944
945 const ResTable::bag_entry* entry = NULL;
946 uint32_t typeSpecFlags;
947 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
948
949 for (ssize_t i=0; i<entryCount; i++) {
950 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
951 block = entry->stringBlock;
952 value = entry->map.value;
953 }
954 entry++;
955 }
956
957 res.unlock();
958
959 if (block < 0) {
Ashok Bhat896043d2014-01-17 16:02:38 +0000960 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 uint32_t ref = ident;
964 if (resolve) {
965 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800966 if (kThrowOnBadId) {
967 if (block == BAD_INDEX) {
968 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
969 return 0;
970 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000973 if (block >= 0) {
974 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
975 }
976
977 return static_cast<jint>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978}
979
980static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
981{
982 AssetManager* am = assetManagerForJavaObject(env, clazz);
983 if (am == NULL) {
984 return 0;
985 }
986 return am->getResources().getTableCount();
987}
988
Ashok Bhat896043d2014-01-17 16:02:38 +0000989static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 jint block)
991{
992 AssetManager* am = assetManagerForJavaObject(env, clazz);
993 if (am == NULL) {
994 return 0;
995 }
Ashok Bhat896043d2014-01-17 16:02:38 +0000996 return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997}
998
999static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
1000 jint cookie)
1001{
1002 AssetManager* am = assetManagerForJavaObject(env, clazz);
1003 if (am == NULL) {
1004 return NULL;
1005 }
Narayan Kamath745d4ef2014-01-27 11:17:22 +00001006 String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001008 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 return NULL;
1010 }
1011 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 return str;
1013}
1014
Adam Lesinskide898ff2014-01-29 18:20:45 -08001015static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
1016{
1017 AssetManager* am = assetManagerForJavaObject(env, clazz);
1018 if (am == NULL) {
1019 return 0;
1020 }
1021
1022 const ResTable& res = am->getResources();
1023
1024 jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
1025 gSparseArrayOffsets.constructor);
1026 const size_t N = res.getBasePackageCount();
1027 for (size_t i = 0; i < N; i++) {
1028 const String16 name = res.getBasePackageName(i);
Dan Albert66987492014-11-20 11:41:21 -08001029 env->CallVoidMethod(
1030 sparseArray, gSparseArrayOffsets.put,
1031 static_cast<jint>(res.getBasePackageId(i)),
1032 env->NewString(reinterpret_cast<const jchar*>(name.string()),
1033 name.size()));
Adam Lesinskide898ff2014-01-29 18:20:45 -08001034 }
1035 return sparseArray;
1036}
1037
Ashok Bhat896043d2014-01-17 16:02:38 +00001038static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039{
1040 AssetManager* am = assetManagerForJavaObject(env, clazz);
1041 if (am == NULL) {
1042 return 0;
1043 }
Ashok Bhat896043d2014-01-17 16:02:38 +00001044 return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045}
1046
1047static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001048 jlong themeHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049{
Ashok Bhat896043d2014-01-17 16:02:38 +00001050 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 delete theme;
1052}
1053
1054static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001055 jlong themeHandle,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 jint styleRes,
1057 jboolean force)
1058{
Ashok Bhat896043d2014-01-17 16:02:38 +00001059 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 theme->applyStyle(styleRes, force ? true : false);
1061}
1062
1063static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001064 jlong destHandle, jlong srcHandle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065{
Ashok Bhat896043d2014-01-17 16:02:38 +00001066 ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
1067 ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 dest->setTo(*src);
1069}
1070
Alan Viverettee54d2452015-05-06 10:41:43 -07001071static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
1072{
1073 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1074 theme->clear();
1075}
1076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077static jint android_content_AssetManager_loadThemeAttributeValue(
Ashok Bhat896043d2014-01-17 16:02:38 +00001078 JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079{
Ashok Bhat896043d2014-01-17 16:02:38 +00001080 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 const ResTable& res(theme->getResTable());
1082
1083 Res_value value;
1084 // XXX value could be different in different configs!
1085 uint32_t typeSpecFlags = 0;
1086 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
1087 uint32_t ref = 0;
1088 if (resolve) {
1089 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001090 if (kThrowOnBadId) {
1091 if (block == BAD_INDEX) {
1092 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1093 return 0;
1094 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
1098}
1099
Alan Viverettec1d52792015-05-05 09:49:03 -07001100static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
1101 jlong themeHandle)
1102{
1103 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1104 return theme->getChangingConfigurations();
1105}
1106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001108 jlong themeHandle, jint pri,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 jstring tag, jstring prefix)
1110{
Ashok Bhat896043d2014-01-17 16:02:38 +00001111 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 const ResTable& res(theme->getResTable());
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001113 (void)res;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 // XXX Need to use params.
1116 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117}
1118
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001119class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1120public:
1121 XmlAttributeFinder(const ResXMLParser* parser)
1122 : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1123 , mParser(parser) {}
1124
1125 inline uint32_t getAttribute(jsize index) const {
1126 return mParser->getAttributeNameResID(index);
1127 }
1128
1129private:
1130 const ResXMLParser* mParser;
1131};
1132
1133class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1134public:
1135 BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1136 : BackTrackingAttributeFinder(start, end) {}
1137
1138 inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1139 return entry->map.name.ident;
1140 }
1141};
1142
Alan Viverette52b999f2014-03-24 18:00:26 -07001143static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1144 jlong themeToken,
1145 jint defStyleAttr,
1146 jint defStyleRes,
1147 jintArray inValues,
1148 jintArray attrs,
1149 jintArray outValues,
1150 jintArray outIndices)
1151{
1152 if (themeToken == 0) {
1153 jniThrowNullPointerException(env, "theme token");
1154 return JNI_FALSE;
1155 }
1156 if (attrs == NULL) {
1157 jniThrowNullPointerException(env, "attrs");
1158 return JNI_FALSE;
1159 }
1160 if (outValues == NULL) {
1161 jniThrowNullPointerException(env, "out values");
1162 return JNI_FALSE;
1163 }
1164
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001165 if (kDebugStyles) {
Dan Albert46d84442014-11-18 16:07:51 -08001166 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
1167 "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001168 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001169
1170 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1171 const ResTable& res = theme->getResTable();
1172 ResTable_config config;
1173 Res_value value;
1174
1175 const jsize NI = env->GetArrayLength(attrs);
1176 const jsize NV = env->GetArrayLength(outValues);
1177 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1178 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1179 return JNI_FALSE;
1180 }
1181
1182 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1183 if (src == NULL) {
1184 return JNI_FALSE;
1185 }
1186
1187 jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1188 const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1189
1190 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1191 jint* dest = baseDest;
1192 if (dest == NULL) {
1193 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1194 return JNI_FALSE;
1195 }
1196
1197 jint* indices = NULL;
1198 int indicesIdx = 0;
1199 if (outIndices != NULL) {
1200 if (env->GetArrayLength(outIndices) > NI) {
1201 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1202 }
1203 }
1204
1205 // Load default style from attribute, if specified...
1206 uint32_t defStyleBagTypeSetFlags = 0;
1207 if (defStyleAttr != 0) {
1208 Res_value value;
1209 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1210 if (value.dataType == Res_value::TYPE_REFERENCE) {
1211 defStyleRes = value.data;
1212 }
1213 }
1214 }
1215
1216 // Now lock down the resource object and start pulling stuff from it.
1217 res.lock();
1218
1219 // Retrieve the default style bag, if requested.
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001220 const ResTable::bag_entry* defStyleStart = NULL;
Alan Viverette52b999f2014-03-24 18:00:26 -07001221 uint32_t defStyleTypeSetFlags = 0;
1222 ssize_t bagOff = defStyleRes != 0
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001223 ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
Alan Viverette52b999f2014-03-24 18:00:26 -07001224 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001225 const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1226 BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
Alan Viverette52b999f2014-03-24 18:00:26 -07001227
1228 // Now iterate through all of the attributes that the client has requested,
1229 // filling in each with whatever data we can find.
1230 ssize_t block = 0;
1231 uint32_t typeSetFlags;
1232 for (jsize ii=0; ii<NI; ii++) {
1233 const uint32_t curIdent = (uint32_t)src[ii];
1234
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001235 if (kDebugStyles) {
1236 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1237 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001238
1239 // Try to find a value for this attribute... we prioritize values
1240 // coming from, first XML attributes, then XML style, then default
1241 // style, and finally the theme.
1242 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001243 value.data = Res_value::DATA_NULL_UNDEFINED;
Alan Viverette52b999f2014-03-24 18:00:26 -07001244 typeSetFlags = 0;
1245 config.density = 0;
1246
1247 // Retrieve the current input value if available.
1248 if (NSV > 0 && srcValues[ii] != 0) {
1249 block = -1;
1250 value.dataType = Res_value::TYPE_ATTRIBUTE;
1251 value.data = srcValues[ii];
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001252 if (kDebugStyles) {
1253 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1254 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001255 }
1256
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001257 if (value.dataType == Res_value::TYPE_NULL) {
1258 const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1259 if (defStyleEntry != defStyleEnd) {
1260 block = defStyleEntry->stringBlock;
Alan Viverette52b999f2014-03-24 18:00:26 -07001261 typeSetFlags = defStyleTypeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001262 value = defStyleEntry->map.value;
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001263 if (kDebugStyles) {
1264 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1265 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001266 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001267 }
1268
1269 uint32_t resid = 0;
1270 if (value.dataType != Res_value::TYPE_NULL) {
1271 // Take care of resolving the found resource to its final value.
1272 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1273 &resid, &typeSetFlags, &config);
1274 if (newBlock >= 0) block = newBlock;
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001275 if (kDebugStyles) {
1276 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1277 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001278 } else {
1279 // If we still don't have a value for this attribute, try to find
1280 // it in the theme!
1281 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1282 if (newBlock >= 0) {
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001283 if (kDebugStyles) {
1284 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1285 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001286 newBlock = res.resolveReference(&value, block, &resid,
1287 &typeSetFlags, &config);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001288 if (kThrowOnBadId) {
1289 if (newBlock == BAD_INDEX) {
1290 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1291 return JNI_FALSE;
1292 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001293 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001294 if (newBlock >= 0) block = newBlock;
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001295 if (kDebugStyles) {
1296 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1297 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001298 }
1299 }
1300
1301 // Deal with the special @null value -- it turns back to TYPE_NULL.
1302 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001303 if (kDebugStyles) {
1304 ALOGI("-> Setting to @null!");
1305 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001306 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001307 value.data = Res_value::DATA_NULL_UNDEFINED;
Alan Viverette52b999f2014-03-24 18:00:26 -07001308 block = -1;
1309 }
1310
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001311 if (kDebugStyles) {
1312 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1313 value.data);
1314 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001315
1316 // Write the final value back to Java.
1317 dest[STYLE_TYPE] = value.dataType;
1318 dest[STYLE_DATA] = value.data;
1319 dest[STYLE_ASSET_COOKIE] =
1320 block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1321 dest[STYLE_RESOURCE_ID] = resid;
1322 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1323 dest[STYLE_DENSITY] = config.density;
1324
1325 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1326 indicesIdx++;
1327 indices[indicesIdx] = ii;
1328 }
1329
1330 dest += STYLE_NUM_ENTRIES;
1331 }
1332
1333 res.unlock();
1334
1335 if (indices != NULL) {
1336 indices[0] = indicesIdx;
1337 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1338 }
1339 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1340 env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1341 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1342
1343 return JNI_TRUE;
1344}
1345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001347 jlong themeToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 jint defStyleAttr,
1349 jint defStyleRes,
Ashok Bhat896043d2014-01-17 16:02:38 +00001350 jlong xmlParserToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 jintArray attrs,
1352 jintArray outValues,
1353 jintArray outIndices)
1354{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001355 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001356 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001357 return JNI_FALSE;
1358 }
1359 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001360 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001361 return JNI_FALSE;
1362 }
1363 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001364 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 return JNI_FALSE;
1366 }
1367
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001368 if (kDebugStyles) {
Dan Albert46d84442014-11-18 16:07:51 -08001369 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
1370 "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
1371 xmlParserToken);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001372 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001373
Ashok Bhat896043d2014-01-17 16:02:38 +00001374 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 const ResTable& res = theme->getResTable();
Ashok Bhat896043d2014-01-17 16:02:38 +00001376 ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
Dianne Hackborn0d221012009-07-29 15:41:19 -07001377 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 Res_value value;
1379
1380 const jsize NI = env->GetArrayLength(attrs);
1381 const jsize NV = env->GetArrayLength(outValues);
1382 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001383 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 return JNI_FALSE;
1385 }
1386
1387 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1388 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 return JNI_FALSE;
1390 }
1391
1392 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1393 jint* dest = baseDest;
1394 if (dest == NULL) {
1395 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 return JNI_FALSE;
1397 }
1398
1399 jint* indices = NULL;
1400 int indicesIdx = 0;
1401 if (outIndices != NULL) {
1402 if (env->GetArrayLength(outIndices) > NI) {
1403 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1404 }
1405 }
1406
1407 // Load default style from attribute, if specified...
1408 uint32_t defStyleBagTypeSetFlags = 0;
1409 if (defStyleAttr != 0) {
1410 Res_value value;
1411 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1412 if (value.dataType == Res_value::TYPE_REFERENCE) {
1413 defStyleRes = value.data;
1414 }
1415 }
1416 }
1417
1418 // Retrieve the style class associated with the current XML tag.
1419 int style = 0;
1420 uint32_t styleBagTypeSetFlags = 0;
1421 if (xmlParser != NULL) {
1422 ssize_t idx = xmlParser->indexOfStyle();
1423 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1424 if (value.dataType == value.TYPE_ATTRIBUTE) {
1425 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1426 value.dataType = Res_value::TYPE_NULL;
1427 }
1428 }
1429 if (value.dataType == value.TYPE_REFERENCE) {
1430 style = value.data;
1431 }
1432 }
1433 }
1434
1435 // Now lock down the resource object and start pulling stuff from it.
1436 res.lock();
1437
1438 // Retrieve the default style bag, if requested.
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001439 const ResTable::bag_entry* defStyleAttrStart = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 uint32_t defStyleTypeSetFlags = 0;
1441 ssize_t bagOff = defStyleRes != 0
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001442 ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001444 const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1445 BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446
1447 // Retrieve the style class bag, if requested.
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001448 const ResTable::bag_entry* styleAttrStart = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 uint32_t styleTypeSetFlags = 0;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001450 bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 styleTypeSetFlags |= styleBagTypeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001452 const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1453 BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454
1455 // Retrieve the XML attributes, if requested.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 static const ssize_t kXmlBlock = 0x10000000;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001457 XmlAttributeFinder xmlAttrFinder(xmlParser);
1458 const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459
1460 // Now iterate through all of the attributes that the client has requested,
1461 // filling in each with whatever data we can find.
1462 ssize_t block = 0;
1463 uint32_t typeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001464 for (jsize ii = 0; ii < NI; ii++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 const uint32_t curIdent = (uint32_t)src[ii];
1466
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001467 if (kDebugStyles) {
1468 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1469 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 // Try to find a value for this attribute... we prioritize values
1472 // coming from, first XML attributes, then XML style, then default
1473 // style, and finally the theme.
1474 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001475 value.data = Res_value::DATA_NULL_UNDEFINED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001477 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001479 // Walk through the xml attributes looking for the requested attribute.
1480 const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1481 if (xmlAttrIdx != xmlAttrEnd) {
1482 // We found the attribute we were looking for.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 block = kXmlBlock;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001484 xmlParser->getAttributeValue(xmlAttrIdx, &value);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001485 if (kDebugStyles) {
1486 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
1489
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001490 if (value.dataType == Res_value::TYPE_NULL) {
1491 // Walk through the style class values looking for the requested attribute.
1492 const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1493 if (styleAttrEntry != styleAttrEnd) {
1494 // We found the attribute we were looking for.
1495 block = styleAttrEntry->stringBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 typeSetFlags = styleTypeSetFlags;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001497 value = styleAttrEntry->map.value;
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001498 if (kDebugStyles) {
1499 ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 }
1503
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001504 if (value.dataType == Res_value::TYPE_NULL) {
1505 // Walk through the default style values looking for the requested attribute.
1506 const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1507 if (defStyleAttrEntry != defStyleAttrEnd) {
1508 // We found the attribute we were looking for.
1509 block = defStyleAttrEntry->stringBlock;
1510 typeSetFlags = styleTypeSetFlags;
1511 value = defStyleAttrEntry->map.value;
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001512 if (kDebugStyles) {
1513 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 }
1517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 uint32_t resid = 0;
1519 if (value.dataType != Res_value::TYPE_NULL) {
1520 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001521 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1522 &resid, &typeSetFlags, &config);
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001523 if (newBlock >= 0) {
1524 block = newBlock;
1525 }
Adam Lesinski11bdd5b2014-11-17 12:17:16 -08001526
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001527 if (kDebugStyles) {
1528 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 } else {
1531 // If we still don't have a value for this attribute, try to find
1532 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1534 if (newBlock >= 0) {
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001535 if (kDebugStyles) {
1536 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1537 }
Dianne Hackborn0d221012009-07-29 15:41:19 -07001538 newBlock = res.resolveReference(&value, block, &resid,
1539 &typeSetFlags, &config);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001540 if (kThrowOnBadId) {
1541 if (newBlock == BAD_INDEX) {
1542 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1543 return JNI_FALSE;
1544 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001545 }
Adam Lesinski11bdd5b2014-11-17 12:17:16 -08001546
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001547 if (newBlock >= 0) {
1548 block = newBlock;
1549 }
Adam Lesinski11bdd5b2014-11-17 12:17:16 -08001550
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001551 if (kDebugStyles) {
1552 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555 }
1556
1557 // Deal with the special @null value -- it turns back to TYPE_NULL.
1558 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001559 if (kDebugStyles) {
1560 ALOGI("-> Setting to @null!");
1561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001563 value.data = Res_value::DATA_NULL_UNDEFINED;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001564 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
1566
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001567 if (kDebugStyles) {
1568 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570
1571 // Write the final value back to Java.
1572 dest[STYLE_TYPE] = value.dataType;
1573 dest[STYLE_DATA] = value.data;
Adam Lesinskia7d1d732014-10-01 18:24:54 -07001574 dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1575 static_cast<jint>(res.getTableCookie(block)) : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 dest[STYLE_RESOURCE_ID] = resid;
1577 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001578 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1581 indicesIdx++;
1582 indices[indicesIdx] = ii;
1583 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 dest += STYLE_NUM_ENTRIES;
1586 }
1587
1588 res.unlock();
1589
1590 if (indices != NULL) {
1591 indices[0] = indicesIdx;
1592 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1593 }
1594 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1595 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1596
1597 return JNI_TRUE;
1598}
1599
1600static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
Ashok Bhat896043d2014-01-17 16:02:38 +00001601 jlong xmlParserToken,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 jintArray attrs,
1603 jintArray outValues,
1604 jintArray outIndices)
1605{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001606 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001607 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001608 return JNI_FALSE;
1609 }
1610 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001611 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001612 return JNI_FALSE;
1613 }
1614 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001615 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 return JNI_FALSE;
1617 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 AssetManager* am = assetManagerForJavaObject(env, clazz);
1620 if (am == NULL) {
1621 return JNI_FALSE;
1622 }
1623 const ResTable& res(am->getResources());
1624 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001625 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 const jsize NI = env->GetArrayLength(attrs);
1629 const jsize NV = env->GetArrayLength(outValues);
1630 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001631 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 return JNI_FALSE;
1633 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1636 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 return JNI_FALSE;
1638 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1641 jint* dest = baseDest;
1642 if (dest == NULL) {
1643 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 return JNI_FALSE;
1645 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 jint* indices = NULL;
1648 int indicesIdx = 0;
1649 if (outIndices != NULL) {
1650 if (env->GetArrayLength(outIndices) > NI) {
1651 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1652 }
1653 }
1654
1655 // Now lock down the resource object and start pulling stuff from it.
1656 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 // Retrieve the XML attributes, if requested.
1659 const jsize NX = xmlParser->getAttributeCount();
1660 jsize ix=0;
1661 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 // Now iterate through all of the attributes that the client has requested,
1666 // filling in each with whatever data we can find.
1667 ssize_t block = 0;
1668 uint32_t typeSetFlags;
1669 for (jsize ii=0; ii<NI; ii++) {
1670 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 // Try to find a value for this attribute...
1673 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001674 value.data = Res_value::DATA_NULL_UNDEFINED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001676 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 // Skip through XML attributes until the end or the next possible match.
Adam Powell908c7482014-10-01 18:11:18 +00001679 while (ix < NX && curIdent > curXmlAttr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 ix++;
1681 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1682 }
1683 // Retrieve the current XML attribute if it matches, and step to next.
1684 if (ix < NX && curIdent == curXmlAttr) {
1685 block = kXmlBlock;
1686 xmlParser->getAttributeValue(ix, &value);
1687 ix++;
1688 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1689 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1692 uint32_t resid = 0;
1693 if (value.dataType != Res_value::TYPE_NULL) {
1694 // Take care of resolving the found resource to its final value.
1695 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001696 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1697 &typeSetFlags, &config);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001698 if (kThrowOnBadId) {
1699 if (newBlock == BAD_INDEX) {
1700 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1701 return JNI_FALSE;
1702 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 if (newBlock >= 0) block = newBlock;
1705 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 // Deal with the special @null value -- it turns back to TYPE_NULL.
1708 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1709 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001710 value.data = Res_value::DATA_NULL_UNDEFINED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 // Write the final value back to Java.
1716 dest[STYLE_TYPE] = value.dataType;
1717 dest[STYLE_DATA] = value.data;
1718 dest[STYLE_ASSET_COOKIE] =
Ashok Bhat896043d2014-01-17 16:02:38 +00001719 block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 dest[STYLE_RESOURCE_ID] = resid;
1721 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001722 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1725 indicesIdx++;
1726 indices[indicesIdx] = ii;
1727 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 dest += STYLE_NUM_ENTRIES;
1730 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 if (indices != NULL) {
1735 indices[0] = indicesIdx;
1736 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1737 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1740 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 return JNI_TRUE;
1743}
1744
1745static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1746 jint id)
1747{
1748 AssetManager* am = assetManagerForJavaObject(env, clazz);
1749 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001750 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 }
1752 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 res.lock();
1755 const ResTable::bag_entry* defStyleEnt = NULL;
1756 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1757 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001758
Ashok Bhat896043d2014-01-17 16:02:38 +00001759 return static_cast<jint>(bagOff);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760}
1761
1762static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1763 jint id,
1764 jintArray outValues)
1765{
1766 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001767 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 return JNI_FALSE;
1769 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 AssetManager* am = assetManagerForJavaObject(env, clazz);
1772 if (am == NULL) {
1773 return JNI_FALSE;
1774 }
1775 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001776 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 Res_value value;
1778 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1783 jint* dest = baseDest;
1784 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001785 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 return JNI_FALSE;
1787 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 // Now lock down the resource object and start pulling stuff from it.
1790 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 const ResTable::bag_entry* arrayEnt = NULL;
1793 uint32_t arrayTypeSetFlags = 0;
1794 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1795 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1796 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 int i = 0;
1799 uint32_t typeSetFlags;
1800 while (i < NV && arrayEnt < endArrayEnt) {
1801 block = arrayEnt->stringBlock;
1802 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001803 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 uint32_t resid = 0;
1807 if (value.dataType != Res_value::TYPE_NULL) {
1808 // Take care of resolving the found resource to its final value.
1809 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001810 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1811 &typeSetFlags, &config);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001812 if (kThrowOnBadId) {
1813 if (newBlock == BAD_INDEX) {
1814 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1815 return JNI_FALSE;
1816 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001817 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 if (newBlock >= 0) block = newBlock;
1819 }
1820
1821 // Deal with the special @null value -- it turns back to TYPE_NULL.
1822 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1823 value.dataType = Res_value::TYPE_NULL;
Alan Viverettef2969402014-10-29 17:09:36 -07001824 value.data = Res_value::DATA_NULL_UNDEFINED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 }
1826
1827 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1828
1829 // Write the final value back to Java.
1830 dest[STYLE_TYPE] = value.dataType;
1831 dest[STYLE_DATA] = value.data;
Ashok Bhat896043d2014-01-17 16:02:38 +00001832 dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 dest[STYLE_RESOURCE_ID] = resid;
1834 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001835 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 dest += STYLE_NUM_ENTRIES;
1837 i+= STYLE_NUM_ENTRIES;
1838 arrayEnt++;
1839 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 return i;
1848}
1849
Ashok Bhat896043d2014-01-17 16:02:38 +00001850static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 jint cookie,
1852 jstring fileName)
1853{
1854 AssetManager* am = assetManagerForJavaObject(env, clazz);
1855 if (am == NULL) {
1856 return 0;
1857 }
1858
Steve Block71f2cf12011-10-20 11:56:00 +01001859 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860
Elliott Hughes69a017b2011-04-08 14:10:28 -07001861 ScopedUtfChars fileName8(env, fileName);
1862 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 return 0;
1864 }
1865
Adam Lesinskide898ff2014-01-29 18:20:45 -08001866 int32_t assetCookie = static_cast<int32_t>(cookie);
1867 Asset* a = assetCookie
1868 ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1869 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870
1871 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001872 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 return 0;
1874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875
Adam Lesinskide898ff2014-01-29 18:20:45 -08001876 const DynamicRefTable* dynamicRefTable =
1877 am->getResources().getDynamicRefTableForCookie(assetCookie);
1878 ResXMLTree* block = new ResXMLTree(dynamicRefTable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1880 a->close();
1881 delete a;
1882
1883 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001884 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 return 0;
1886 }
1887
Ashok Bhat896043d2014-01-17 16:02:38 +00001888 return reinterpret_cast<jlong>(block);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889}
1890
1891static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1892 jint arrayResId)
1893{
1894 AssetManager* am = assetManagerForJavaObject(env, clazz);
1895 if (am == NULL) {
1896 return NULL;
1897 }
1898 const ResTable& res(am->getResources());
1899
1900 const ResTable::bag_entry* startOfBag;
1901 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1902 if (N < 0) {
1903 return NULL;
1904 }
1905
1906 jintArray array = env->NewIntArray(N * 2);
1907 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 res.unlockBag(startOfBag);
1909 return NULL;
1910 }
1911
1912 Res_value value;
1913 const ResTable::bag_entry* bag = startOfBag;
1914 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1915 jint stringIndex = -1;
1916 jint stringBlock = 0;
1917 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 // Take care of resolving the found resource to its final value.
1920 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1921 if (value.dataType == Res_value::TYPE_STRING) {
1922 stringIndex = value.data;
1923 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001924
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001925 if (kThrowOnBadId) {
1926 if (stringBlock == BAD_INDEX) {
1927 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1928 return array;
1929 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001930 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 //todo: It might be faster to allocate a C array to contain
1933 // the blocknums and indices, put them in there and then
1934 // do just one SetIntArrayRegion()
1935 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1936 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1937 j = j + 2;
1938 }
1939 res.unlockBag(startOfBag);
1940 return array;
1941}
1942
1943static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1944 jint arrayResId)
1945{
1946 AssetManager* am = assetManagerForJavaObject(env, clazz);
1947 if (am == NULL) {
1948 return NULL;
1949 }
1950 const ResTable& res(am->getResources());
1951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 const ResTable::bag_entry* startOfBag;
1953 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1954 if (N < 0) {
1955 return NULL;
1956 }
1957
Vladimir Markoaa5fe3d2013-06-17 12:46:22 +01001958 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001959 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 res.unlockBag(startOfBag);
1961 return NULL;
1962 }
1963
1964 Res_value value;
1965 const ResTable::bag_entry* bag = startOfBag;
1966 size_t strLen = 0;
1967 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1968 value = bag->map.value;
1969 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 // Take care of resolving the found resource to its final value.
1972 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001973 if (kThrowOnBadId) {
1974 if (block == BAD_INDEX) {
1975 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1976 return array;
1977 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001978 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001980 const ResStringPool* pool = res.getTableStringBlock(block);
1981 const char* str8 = pool->string8At(value.data, &strLen);
1982 if (str8 != NULL) {
1983 str = env->NewStringUTF(str8);
1984 } else {
1985 const char16_t* str16 = pool->stringAt(value.data, &strLen);
Dan Albert66987492014-11-20 11:41:21 -08001986 str = env->NewString(reinterpret_cast<const jchar*>(str16),
1987 strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001988 }
1989
1990 // If one of our NewString{UTF} calls failed due to memory, an
1991 // exception will be pending.
1992 if (env->ExceptionCheck()) {
1993 res.unlockBag(startOfBag);
1994 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 }
Kenny Root780d2a12010-02-22 22:36:26 -08001996
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001997 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001998
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001999 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
2000 // If we have a large amount of strings in our array, we might
2001 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07002002 env->DeleteLocalRef(str);
2003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 }
2005 res.unlockBag(startOfBag);
2006 return array;
2007}
2008
2009static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
2010 jint arrayResId)
2011{
2012 AssetManager* am = assetManagerForJavaObject(env, clazz);
2013 if (am == NULL) {
2014 return NULL;
2015 }
2016 const ResTable& res(am->getResources());
2017
2018 const ResTable::bag_entry* startOfBag;
2019 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
2020 if (N < 0) {
2021 return NULL;
2022 }
2023
2024 jintArray array = env->NewIntArray(N);
2025 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 res.unlockBag(startOfBag);
2027 return NULL;
2028 }
2029
2030 Res_value value;
2031 const ResTable::bag_entry* bag = startOfBag;
2032 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
2033 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07002034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 // Take care of resolving the found resource to its final value.
2036 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08002037 if (kThrowOnBadId) {
2038 if (block == BAD_INDEX) {
2039 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
2040 return array;
2041 }
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08002042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 if (value.dataType >= Res_value::TYPE_FIRST_INT
2044 && value.dataType <= Res_value::TYPE_LAST_INT) {
2045 int intVal = value.data;
2046 env->SetIntArrayRegion(array, i, 1, &intVal);
2047 }
2048 }
2049 res.unlockBag(startOfBag);
2050 return array;
2051}
2052
Jon Miranda042ad632014-09-03 17:57:35 -07002053static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
2054 jint styleId)
2055{
2056 AssetManager* am = assetManagerForJavaObject(env, clazz);
2057 if (am == NULL) {
2058 return NULL;
2059 }
2060 const ResTable& res(am->getResources());
2061
2062 const ResTable::bag_entry* startOfBag;
2063 const ssize_t N = res.lockBag(styleId, &startOfBag);
2064 if (N < 0) {
2065 return NULL;
2066 }
2067
2068 jintArray array = env->NewIntArray(N);
2069 if (array == NULL) {
2070 res.unlockBag(startOfBag);
2071 return NULL;
2072 }
2073
Jon Miranda042ad632014-09-03 17:57:35 -07002074 const ResTable::bag_entry* bag = startOfBag;
2075 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
2076 int resourceId = bag->map.name.ident;
2077 env->SetIntArrayRegion(array, i, 1, &resourceId);
2078 }
2079 res.unlockBag(startOfBag);
2080 return array;
2081}
2082
Mårten Kongstad48d22322014-01-31 14:43:27 +01002083static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084{
Mårten Kongstad48d22322014-01-31 14:43:27 +01002085 if (isSystem) {
2086 verifySystemIdmaps();
2087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 AssetManager* am = new AssetManager();
2089 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07002090 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 return;
2092 }
2093
2094 am->addDefaultAssets();
2095
Steve Block71f2cf12011-10-20 11:56:00 +01002096 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
Ashok Bhat896043d2014-01-17 16:02:38 +00002097 env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098}
2099
2100static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
2101{
2102 AssetManager* am = (AssetManager*)
Ashok Bhat896043d2014-01-17 16:02:38 +00002103 (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01002104 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 if (am != NULL) {
2106 delete am;
Ashok Bhat896043d2014-01-17 16:02:38 +00002107 env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 }
2109}
2110
2111static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2112{
2113 return Asset::getGlobalCount();
2114}
2115
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07002116static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2117{
2118 String8 alloc = Asset::getAssetAllocations();
2119 if (alloc.length() <= 0) {
2120 return NULL;
2121 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07002122
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07002123 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07002124 return str;
2125}
2126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2128{
2129 return AssetManager::getGlobalCount();
2130}
2131
2132// ----------------------------------------------------------------------------
2133
2134/*
2135 * JNI registration.
2136 */
Daniel Micay76f6a862015-09-19 17:31:01 -04002137static const JNINativeMethod gAssetManagerMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 /* name, signature, funcPtr */
2139
2140 // Basic asset stuff.
Ashok Bhat896043d2014-01-17 16:02:38 +00002141 { "openAsset", "(Ljava/lang/String;I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 (void*) android_content_AssetManager_openAsset },
2143 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2144 (void*) android_content_AssetManager_openAssetFd },
Ashok Bhat896043d2014-01-17 16:02:38 +00002145 { "openNonAssetNative", "(ILjava/lang/String;I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 (void*) android_content_AssetManager_openNonAssetNative },
2147 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2148 (void*) android_content_AssetManager_openNonAssetFdNative },
2149 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
2150 (void*) android_content_AssetManager_list },
Ashok Bhat896043d2014-01-17 16:02:38 +00002151 { "destroyAsset", "(J)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 (void*) android_content_AssetManager_destroyAsset },
Ashok Bhat896043d2014-01-17 16:02:38 +00002153 { "readAssetChar", "(J)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 (void*) android_content_AssetManager_readAssetChar },
Ashok Bhat896043d2014-01-17 16:02:38 +00002155 { "readAsset", "(J[BII)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 (void*) android_content_AssetManager_readAsset },
Ashok Bhat896043d2014-01-17 16:02:38 +00002157 { "seekAsset", "(JJI)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 (void*) android_content_AssetManager_seekAsset },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002159 { "getAssetLength", "!(J)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 (void*) android_content_AssetManager_getAssetLength },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002161 { "getAssetRemainingLength", "!(J)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 (void*) android_content_AssetManager_getAssetRemainingLength },
Tao Baia6d7e3f2015-09-01 18:49:54 -07002163 { "addAssetPathNative", "(Ljava/lang/String;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 (void*) android_content_AssetManager_addAssetPath },
Mårten Kongstad30113132014-11-07 10:52:17 +01002165 { "addOverlayPathNative", "(Ljava/lang/String;)I",
Mårten Kongstad48d22322014-01-31 14:43:27 +01002166 (void*) android_content_AssetManager_addOverlayPath },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 { "isUpToDate", "()Z",
2168 (void*) android_content_AssetManager_isUpToDate },
2169
2170 // Resources.
2171 { "setLocale", "(Ljava/lang/String;)V",
2172 (void*) android_content_AssetManager_setLocale },
2173 { "getLocales", "()[Ljava/lang/String;",
2174 (void*) android_content_AssetManager_getLocales },
Filip Gruszczynski23493322015-07-29 17:02:59 -07002175 { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
2176 (void*) android_content_AssetManager_getSizeConfigurations },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002177 { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 (void*) android_content_AssetManager_setConfiguration },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002179 { "getResourceIdentifier","!(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002180 (void*) android_content_AssetManager_getResourceIdentifier },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002181 { "getResourceName","!(I)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 (void*) android_content_AssetManager_getResourceName },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002183 { "getResourcePackageName","!(I)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 (void*) android_content_AssetManager_getResourcePackageName },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002185 { "getResourceTypeName","!(I)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 (void*) android_content_AssetManager_getResourceTypeName },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002187 { "getResourceEntryName","!(I)Ljava/lang/String;",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 (void*) android_content_AssetManager_getResourceEntryName },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002189 { "loadResourceValue","!(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 (void*) android_content_AssetManager_loadResourceValue },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002191 { "loadResourceBagValue","!(IILandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 (void*) android_content_AssetManager_loadResourceBagValue },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002193 { "getStringBlockCount","!()I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 (void*) android_content_AssetManager_getStringBlockCount },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002195 { "getNativeStringBlock","!(I)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 (void*) android_content_AssetManager_getNativeStringBlock },
2197 { "getCookieName","(I)Ljava/lang/String;",
2198 (void*) android_content_AssetManager_getCookieName },
Adam Lesinskide898ff2014-01-29 18:20:45 -08002199 { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2200 (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002201
2202 // Themes.
Ashok Bhat896043d2014-01-17 16:02:38 +00002203 { "newTheme", "()J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 (void*) android_content_AssetManager_newTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00002205 { "deleteTheme", "(J)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 (void*) android_content_AssetManager_deleteTheme },
Ashok Bhat896043d2014-01-17 16:02:38 +00002207 { "applyThemeStyle", "(JIZ)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 (void*) android_content_AssetManager_applyThemeStyle },
Ashok Bhat896043d2014-01-17 16:02:38 +00002209 { "copyTheme", "(JJ)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 (void*) android_content_AssetManager_copyTheme },
Alan Viverettee54d2452015-05-06 10:41:43 -07002211 { "clearTheme", "(J)V",
2212 (void*) android_content_AssetManager_clearTheme },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002213 { "loadThemeAttributeValue", "!(JILandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 (void*) android_content_AssetManager_loadThemeAttributeValue },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002215 { "getThemeChangingConfigurations", "!(J)I",
Alan Viverettec1d52792015-05-05 09:49:03 -07002216 (void*) android_content_AssetManager_getThemeChangingConfigurations },
Ashok Bhat896043d2014-01-17 16:02:38 +00002217 { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 (void*) android_content_AssetManager_dumpTheme },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002219 { "applyStyle","!(JIIJ[I[I[I)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 (void*) android_content_AssetManager_applyStyle },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002221 { "resolveAttrs","!(JII[I[I[I[I)Z",
Alan Viverette607bd842014-09-12 12:36:35 -07002222 (void*) android_content_AssetManager_resolveAttrs },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002223 { "retrieveAttributes","!(J[I[I[I)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 (void*) android_content_AssetManager_retrieveAttributes },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002225 { "getArraySize","!(I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 (void*) android_content_AssetManager_getArraySize },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002227 { "retrieveArray","!(I[I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 (void*) android_content_AssetManager_retrieveArray },
2229
2230 // XML files.
Ashok Bhat896043d2014-01-17 16:02:38 +00002231 { "openXmlAssetNative", "(ILjava/lang/String;)J",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 (void*) android_content_AssetManager_openXmlAssetNative },
2233
2234 // Arrays.
2235 { "getArrayStringResource","(I)[Ljava/lang/String;",
2236 (void*) android_content_AssetManager_getArrayStringResource },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002237 { "getArrayStringInfo","!(I)[I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 (void*) android_content_AssetManager_getArrayStringInfo },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002239 { "getArrayIntResource","!(I)[I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 (void*) android_content_AssetManager_getArrayIntResource },
Jeff Sharkey46cfd932015-11-02 18:39:45 -08002241 { "getStyleAttributes","!(I)[I",
Jon Miranda042ad632014-09-03 17:57:35 -07002242 (void*) android_content_AssetManager_getStyleAttributes },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243
2244 // Bookkeeping.
Mårten Kongstad48d22322014-01-31 14:43:27 +01002245 { "init", "(Z)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 (void*) android_content_AssetManager_init },
2247 { "destroy", "()V",
2248 (void*) android_content_AssetManager_destroy },
2249 { "getGlobalAssetCount", "()I",
2250 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07002251 { "getAssetAllocations", "()Ljava/lang/String;",
2252 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 { "getGlobalAssetManagerCount", "()I",
Andreas Gampe32812612014-11-11 00:16:00 -08002254 (void*) android_content_AssetManager_getGlobalAssetManagerCount },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255};
2256
2257int register_android_content_AssetManager(JNIEnv* env)
2258{
Andreas Gampe987f79f2014-11-18 17:29:46 -08002259 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2260 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2261 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2262 gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2263 "Ljava/lang/CharSequence;");
2264 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2265 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2266 gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2267 "changingConfigurations", "I");
2268 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002269
Andreas Gampe987f79f2014-11-18 17:29:46 -08002270 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2271 gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2272 "Landroid/os/ParcelFileDescriptor;");
2273 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2274 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275
Andreas Gampe987f79f2014-11-18 17:29:46 -08002276 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2277 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278
Andreas Gampe987f79f2014-11-18 17:29:46 -08002279 jclass stringClass = FindClassOrDie(env, "java/lang/String");
2280 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281
Andreas Gampe987f79f2014-11-18 17:29:46 -08002282 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2283 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2284 gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2285 "<init>", "()V");
2286 gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2287 "(ILjava/lang/Object;)V");
Adam Lesinskide898ff2014-01-29 18:20:45 -08002288
Filip Gruszczynski23493322015-07-29 17:02:59 -07002289 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
2290 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
2291 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
2292 "<init>", "()V");
2293 gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
2294 "smallestScreenWidthDp", "I");
2295 gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
2296 "screenWidthDp", "I");
2297 gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
2298 "screenHeightDp", "I");
2299
Andreas Gampe987f79f2014-11-18 17:29:46 -08002300 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2301 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002302}
2303
2304}; // namespace android