diff options
author | Amit Pundir <amit.pundir@linaro.org> | 2014-04-21 12:12:36 +0530 |
---|---|---|
committer | Amit Pundir <amit.pundir@linaro.org> | 2014-04-21 12:12:36 +0530 |
commit | 37414fd63219296dba22e1d2225175f0215ddbed (patch) | |
tree | 40ed0f720e8379f36d2165bb7ff1eeecff36d40e | |
parent | 7ea7f564e430527ef5717d15a5bb22289c0f4d03 (diff) | |
parent | 2a52862db5257edcafa137276ce3d8dc54cd443e (diff) | |
download | base-37414fd63219296dba22e1d2225175f0215ddbed.tar.gz |
Merge master
* aosp/master:
Use LOCAL_JNI_SHARED_LIBRARIES to install JNI libs.
Fix warning introduced by recent psuedolocalizer change.
jni: binder ptrdiff_t compile issues
jni: binder 64-bit compile issues
Fix improper use of JNI_ABORT for operations where Java objects are written.
Add BiCubic resize instrinsic
frameworks: 64 bit compile issues
Native Runtime: Add LOG_ID_CRASH
Pseudolocalizer improvements.
-rw-r--r-- | core/java/android/util/Log.java | 1 | ||||
-rw-r--r-- | core/java/com/android/internal/os/RuntimeInit.java | 13 | ||||
-rw-r--r-- | core/jni/android_database_CursorWindow.cpp | 5 | ||||
-rw-r--r-- | core/jni/android_net_TrafficStats.cpp | 15 | ||||
-rw-r--r-- | core/jni/android_os_Debug.cpp | 5 | ||||
-rw-r--r-- | core/jni/android_util_Binder.cpp | 19 | ||||
-rw-r--r-- | media/jni/android_media_MediaRecorder.cpp | 14 | ||||
-rw-r--r-- | media/jni/mediaeditor/VideoEditorMain.cpp | 9 | ||||
-rw-r--r-- | packages/DefaultContainerService/Android.mk | 2 | ||||
-rw-r--r-- | packages/services/PacProcessor/Android.mk | 2 | ||||
-rw-r--r-- | rs/java/android/renderscript/ScriptIntrinsicResize.java | 113 | ||||
-rw-r--r-- | rs/jni/android_renderscript_RenderScript.cpp | 44 | ||||
-rw-r--r-- | tools/aapt/Bundle.h | 19 | ||||
-rw-r--r-- | tools/aapt/Command.cpp | 7 | ||||
-rw-r--r-- | tools/aapt/ResourceFilter.cpp | 6 | ||||
-rw-r--r-- | tools/aapt/ResourceFilter.h | 9 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 94 | ||||
-rw-r--r-- | tools/aapt/XMLNode.cpp | 42 | ||||
-rw-r--r-- | tools/aapt/XMLNode.h | 2 | ||||
-rw-r--r-- | tools/aapt/pseudolocalize.cpp | 251 | ||||
-rw-r--r-- | tools/aapt/pseudolocalize.h | 11 |
21 files changed, 529 insertions, 154 deletions
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index abd173a50721..2b8107224e42 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -352,6 +352,7 @@ public final class Log { /** @hide */ public static final int LOG_ID_RADIO = 1; /** @hide */ public static final int LOG_ID_EVENTS = 2; /** @hide */ public static final int LOG_ID_SYSTEM = 3; + /** @hide */ public static final int LOG_ID_CRASH = 4; /** @hide */ public static native int println_native(int bufID, int priority, String tag, String msg); diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 5538dca2a4fa..4a26b4b17b6f 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -55,6 +55,11 @@ public class RuntimeInit { private static final native void nativeFinishInit(); private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup); + private static int Clog_e(String tag, String msg, Throwable tr) { + return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + /** * Use this to log a message when a thread exits due to an uncaught * exception. The framework catches these for the main threads, so @@ -68,7 +73,7 @@ public class RuntimeInit { mCrashing = true; if (mApplicationObject == null) { - Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); + Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n"); @@ -77,7 +82,7 @@ public class RuntimeInit { message.append("Process: ").append(processName).append(", "); } message.append("PID: ").append(Process.myPid()); - Slog.e(TAG, message.toString(), e); + Clog_e(TAG, message.toString(), e); } // Bring up crash dialog, wait for it to be dismissed @@ -85,9 +90,9 @@ public class RuntimeInit { mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); } catch (Throwable t2) { try { - Slog.e(TAG, "Error reporting crash", t2); + Clog_e(TAG, "Error reporting crash", t2); } catch (Throwable t3) { - // Even Slog.e() fails! Oh well. + // Even Clog_e() fails! Oh well. } } finally { // Try everything to make sure this process goes away. diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 67f387920f57..af6cc72b588b 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -17,6 +17,7 @@ #undef LOG_TAG #define LOG_TAG "CursorWindow" +#include <inttypes.h> #include <jni.h> #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> @@ -225,7 +226,7 @@ static jstring nativeGetString(JNIEnv* env, jclass clazz, jlong windowPtr, } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { int64_t value = window->getFieldSlotValueLong(fieldSlot); char buf[32]; - snprintf(buf, sizeof(buf), "%lld", value); + snprintf(buf, sizeof(buf), "%" PRId64, value); return env->NewStringUTF(buf); } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { double value = window->getFieldSlotValueDouble(fieldSlot); @@ -314,7 +315,7 @@ static void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jlong windowPtr, } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { int64_t value = window->getFieldSlotValueLong(fieldSlot); char buf[32]; - snprintf(buf, sizeof(buf), "%lld", value); + snprintf(buf, sizeof(buf), "%" PRId64, value); fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf)); } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { double value = window->getFieldSlotValueDouble(fieldSlot); diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index f904b62e2918..031637f41db1 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -19,6 +19,7 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> @@ -85,9 +86,9 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets; while (fgets(buffer, sizeof(buffer), fp) != NULL) { - int matched = sscanf(buffer, "%31s %llu %llu %llu %llu " - "%*u %llu %*u %*u %*u %*u " - "%*u %llu %*u %*u %*u %*u", cur_iface, &rxBytes, + int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64 + " %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u " + "%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes, &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets); if (matched >= 5) { if (matched == 7) { @@ -129,9 +130,11 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) { uint64_t tag, rxBytes, rxPackets, txBytes, txPackets; while (fgets(buffer, sizeof(buffer), fp) != NULL) { - if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &idx, - iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, &txBytes, - &txPackets) == 9) { + if (sscanf(buffer, + "%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64 + " %" SCNu64 " %" SCNu64 "", + &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, + &txBytes, &txPackets) == 9) { if (uid == cur_uid && tag == 0L) { stats->rxBytes += rxBytes; stats->rxPackets += rxPackets; diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index d4873d6a7a12..86207f0a3ea2 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -24,6 +24,7 @@ #include <cutils/log.h> #include <fcntl.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -824,9 +825,9 @@ static void dumpNativeHeap(FILE* fp) break; } else { #ifdef __LP64__ - fprintf(fp, " %016x", backtrace[bt]); + fprintf(fp, " %016" PRIxPTR, backtrace[bt]); #else - fprintf(fp, " %08x", backtrace[bt]); + fprintf(fp, " %08" PRIxPTR, backtrace[bt]); #endif } } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 475e926eafc4..662af895e04f 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -23,6 +23,7 @@ #include "JNIHelp.h" #include <fcntl.h> +#include <inttypes.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> @@ -334,7 +335,7 @@ public: if (b == NULL) { b = new JavaBBinder(env, obj); mBinder = b; - ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n", + ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n", b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount()); } @@ -697,9 +698,9 @@ void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, "Not allowed to write file descriptors here"); break; default: - ALOGE("Unknown binder error code. 0x%x", err); + ALOGE("Unknown binder error code. 0x%" PRIx32, err); String8 msg; - msg.appendFormat("Unknown binder error code. 0x%x", err); + msg.appendFormat("Unknown binder error code. 0x%" PRIx32, err); // RemoteException is a checked exception, only throw from certain methods. jniThrowException(env, canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException", msg.string()); @@ -733,7 +734,7 @@ static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, if (uid > 0 && uid < 999) { // In Android currently there are no uids in this range. char buf[128]; - sprintf(buf, "Restoring bad calling ident: 0x%Lx", token); + sprintf(buf, "Restoring bad calling ident: 0x%" PRIx64, token); jniThrowException(env, "java/lang/IllegalStateException", buf); return; } @@ -965,8 +966,8 @@ static bool push_eventlog_string(char** pos, const char* end, const char* str) { jint len = strlen(str); int space_needed = 1 + sizeof(len) + len; if (end - *pos < space_needed) { - ALOGW("not enough space for string. remain=%d; needed=%d", - (end - *pos), space_needed); + ALOGW("not enough space for string. remain=%" PRIdPTR "; needed=%d", + end - *pos, space_needed); return false; } **pos = EVENT_TYPE_STRING; @@ -981,8 +982,8 @@ static bool push_eventlog_string(char** pos, const char* end, const char* str) { static bool push_eventlog_int(char** pos, const char* end, jint val) { int space_needed = 1 + sizeof(val); if (end - *pos < space_needed) { - ALOGW("not enough space for int. remain=%d; needed=%d", - (end - *pos), space_needed); + ALOGW("not enough space for int. remain=%" PRIdPTR "; needed=%d", + end - *pos, space_needed); return false; } **pos = EVENT_TYPE_INT; @@ -1068,7 +1069,7 @@ static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, return JNI_FALSE; } - ALOGV("Java code calling transact on %p in Java object %p with code %d\n", + ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n", target, obj, code); #if ENABLE_BINDER_SAMPLE diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 0cfd2ffd6718..b74d0fb3a7fa 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -14,6 +14,13 @@ * limitations under the License. */ +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <unistd.h> + //#define LOG_NDEBUG 0 #define LOG_TAG "MediaRecorderJNI" #include <utils/Log.h> @@ -22,11 +29,6 @@ #include <camera/ICameraService.h> #include <camera/Camera.h> #include <media/mediarecorder.h> -#include <stdio.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> #include <utils/threads.h> #include "jni.h" @@ -303,7 +305,7 @@ android_media_MediaRecorder_setMaxFileSize( sp<MediaRecorder> mr = getMediaRecorder(env, thiz); char params[64]; - sprintf(params, "max-filesize=%lld", max_filesize_bytes); + sprintf(params, "max-filesize=%" PRId64, max_filesize_bytes); process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxFileSize failed."); } diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp index c0f6a950eeab..0894d746a7ec 100644 --- a/media/jni/mediaeditor/VideoEditorMain.cpp +++ b/media/jni/mediaeditor/VideoEditorMain.cpp @@ -16,6 +16,7 @@ #define LOG_NDEBUG 1 #define LOG_TAG "VideoEditorMain" #include <dlfcn.h> +#include <inttypes.h> #include <stdio.h> #include <unistd.h> #include <utils/Log.h> @@ -3371,7 +3372,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead); if (inputFileHandle == M4OSA_NULL) { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", - "M4MA_generateAudioGraphFile: Cannot open input file 0x%lx", err); + "M4MA_generateAudioGraphFile: Cannot open input file 0x%" PRIx32, err); return err; } @@ -3405,7 +3406,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16); } else { VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", - "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%lx", + "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%" PRIx32, M4ERR_ALLOC); return M4ERR_ALLOC; } @@ -3445,7 +3446,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, if (err != M4NO_ERROR) { // if out value of bytes-read is 0, break if ( numBytesToRead == 0) { - VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%lx", + VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%" PRIx32, numBytesToRead); break; /* stop if file is empty or EOF */ } @@ -3497,7 +3498,7 @@ M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL, } while (numBytesToRead != 0); - VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%lx", volumeValuesCount); + VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%" PRIx32, volumeValuesCount); /* if some error occured in fwrite */ if (numBytesToRead != 0) { diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk index 99611683c6f4..0de2c1fe4a6a 100644 --- a/packages/DefaultContainerService/Android.mk +++ b/packages/DefaultContainerService/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DefaultContainerService -LOCAL_REQUIRED_MODULES := libdefcontainer_jni +LOCAL_JNI_SHARED_LIBRARIES := libdefcontainer_jni LOCAL_CERTIFICATE := platform diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk index d9566d5022d1..3c4e951f9e73 100644 --- a/packages/services/PacProcessor/Android.mk +++ b/packages/services/PacProcessor/Android.mk @@ -25,7 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PacProcessor LOCAL_CERTIFICATE := platform -LOCAL_REQUIRED_MODULES := libjni_pacprocessor +LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor include $(BUILD_PACKAGE) diff --git a/rs/java/android/renderscript/ScriptIntrinsicResize.java b/rs/java/android/renderscript/ScriptIntrinsicResize.java new file mode 100644 index 000000000000..cc37120f8030 --- /dev/null +++ b/rs/java/android/renderscript/ScriptIntrinsicResize.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +/** + * Intrinsic for performing a resize of a 2D allocation. + * @hide + */ +public final class ScriptIntrinsicResize extends ScriptIntrinsic { + private Allocation mInput; + + private ScriptIntrinsicResize(long id, RenderScript rs) { + super(id, rs); + } + + /** + * Supported elements types are {@link Element#U8}, {@link + * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4} + * + * @param rs The RenderScript context + * + * @return ScriptIntrinsicResize + */ + public static ScriptIntrinsicResize create(RenderScript rs) { + long id = rs.nScriptIntrinsicCreate(12, 0); + ScriptIntrinsicResize si = new ScriptIntrinsicResize(id, rs); + return si; + + } + + /** + * Set the input of the resize. + * Must match the element type supplied during create. + * + * @param ain The input allocation. + */ + public void setInput(Allocation ain) { + Element e = ain.getElement(); + if (!e.isCompatible(Element.U8(mRS)) && + !e.isCompatible(Element.U8_2(mRS)) && + !e.isCompatible(Element.U8_3(mRS)) && + !e.isCompatible(Element.U8_4(mRS))) { + throw new RSIllegalArgumentException("Unsuported element type."); + } + + mInput = ain; + setVar(0, ain); + } + + /** + * Get a FieldID for the input field of this intrinsic. + * + * @return Script.FieldID The FieldID object. + */ + public Script.FieldID getFieldID_Input() { + return createFieldID(0, null); + } + + + /** + * Resize copy the input allocation to the output specified. The + * Allocation is rescaled if necessary using bi-cubic + * interpolation. + * + * @param aout Output allocation. Element type must match + * current input. Must not be same as input. + */ + public void forEach_bicubic(Allocation aout) { + if (aout == mInput) { + throw new RSIllegalArgumentException("Output cannot be same as Input."); + } + forEach_bicubic(aout, null); + } + + /** + * Resize copy the input allocation to the output specified. The + * Allocation is rescaled if necessary using bi-cubic + * interpolation. + * + * @param aout Output allocation. Element type must match + * current input. + * @param opt LaunchOptions for clipping + */ + public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) { + forEach(0, null, aout, null, opt); + } + + /** + * Get a KernelID for this intrinsic kernel. + * + * @return Script.KernelID The KernelID object. + */ + public Script.KernelID getKernelID_bicubic() { + return createKernelID(0, 2, null, null); + } + + +} + diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index 9b89eb9ddce2..0d75f4c8a5d6 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -50,24 +50,29 @@ using namespace android; -#define PER_ARRAY_TYPE(flag, fnc, ...) { \ +#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) { \ jint len = 0; \ void *ptr = NULL; \ size_t typeBytes = 0; \ + jint relFlag = 0; \ + if (readonly) { \ + /* The on-release mode should only be JNI_ABORT for read-only accesses. */ \ + relFlag = JNI_ABORT; \ + } \ switch(dataType) { \ case RS_TYPE_FLOAT_32: \ len = _env->GetArrayLength((jfloatArray)data); \ ptr = _env->GetFloatArrayElements((jfloatArray)data, flag); \ typeBytes = 4; \ fnc(__VA_ARGS__); \ - _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, JNI_ABORT); \ + _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag); \ return; \ case RS_TYPE_FLOAT_64: \ len = _env->GetArrayLength((jdoubleArray)data); \ ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag); \ typeBytes = 8; \ fnc(__VA_ARGS__); \ - _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, JNI_ABORT);\ + _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_8: \ case RS_TYPE_UNSIGNED_8: \ @@ -75,7 +80,7 @@ using namespace android; ptr = _env->GetByteArrayElements((jbyteArray)data, flag); \ typeBytes = 1; \ fnc(__VA_ARGS__); \ - _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, JNI_ABORT); \ + _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_16: \ case RS_TYPE_UNSIGNED_16: \ @@ -83,7 +88,7 @@ using namespace android; ptr = _env->GetShortArrayElements((jshortArray)data, flag); \ typeBytes = 2; \ fnc(__VA_ARGS__); \ - _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, JNI_ABORT); \ + _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_32: \ case RS_TYPE_UNSIGNED_32: \ @@ -91,7 +96,7 @@ using namespace android; ptr = _env->GetIntArrayElements((jintArray)data, flag); \ typeBytes = 4; \ fnc(__VA_ARGS__); \ - _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, JNI_ABORT); \ + _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag); \ return; \ case RS_TYPE_SIGNED_64: \ case RS_TYPE_UNSIGNED_64: \ @@ -99,7 +104,7 @@ using namespace android; ptr = _env->GetLongArrayElements((jlongArray)data, flag); \ typeBytes = 8; \ fnc(__VA_ARGS__); \ - _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, JNI_ABORT); \ + _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag); \ return; \ default: \ break; \ @@ -675,6 +680,7 @@ static void ReleaseBitmapCallback(void *bmp) } +// Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod, jint count, jobject data, jint sizeBytes, jint dataType) @@ -682,9 +688,10 @@ nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint off RsAllocation *alloc = (RsAllocation *)_alloc; LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes, dataType); - PER_ARRAY_TYPE(NULL, rsAllocation1DData, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); + PER_ARRAY_TYPE(NULL, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); } +// Copies from the Java array data into the Allocation pointed to by alloc. static void // native void rsnAllocationElementData1D(long con, long id, int xoff, int compIdx, byte[] d, int sizeBytes); nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, jint sizeBytes) @@ -696,6 +703,7 @@ nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, ji _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); } +// Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face, jint w, jint h, jobject data, jint sizeBytes, jint dataType) @@ -704,9 +712,11 @@ nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face; LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType); - PER_ARRAY_TYPE(NULL, rsAllocation2DData, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); + PER_ARRAY_TYPE(NULL, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); } +// Copies from the Allocation pointed to by srcAlloc into the Allocation +// pointed to by dstAlloc. static void nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con, jlong dstAlloc, jint dstXoff, jint dstYoff, @@ -731,6 +741,7 @@ nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con, srcMip, srcFace); } +// Copies from the Java object data into the Allocation pointed to by _alloc. static void nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod, jint w, jint h, jint d, jobject data, int sizeBytes, int dataType) @@ -738,9 +749,11 @@ nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof RsAllocation *alloc = (RsAllocation *)_alloc; LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i), h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes); - PER_ARRAY_TYPE(NULL, rsAllocation3DData, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0); + PER_ARRAY_TYPE(NULL, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0); } +// Copies from the Allocation pointed to by srcAlloc into the Allocation +// pointed to by dstAlloc. static void nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con, jlong dstAlloc, jint dstXoff, jint dstYoff, jint dstZoff, @@ -764,14 +777,16 @@ nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con, } +// Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType) { RsAllocation *alloc = (RsAllocation *)_alloc; LOG_API("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc); - PER_ARRAY_TYPE(0, rsAllocationRead, (RsContext)con, alloc, ptr, len * typeBytes); + PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes); } +// Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod, jint count, jobject data, int sizeBytes, int dataType) @@ -779,9 +794,10 @@ nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint off RsAllocation *alloc = (RsAllocation *)_alloc; LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType); - PER_ARRAY_TYPE(0, rsAllocation1DRead, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); + PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes); } +// Copies from the Allocation pointed to by _alloc into the Java object data. static void nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face, jint w, jint h, jobject data, int sizeBytes, int dataType) @@ -790,7 +806,7 @@ nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xof RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face; LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType); - PER_ARRAY_TYPE(0, rsAllocation2DRead, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); + PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0); } static jlong @@ -1026,7 +1042,7 @@ nScriptGetVarV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jint len = _env->GetArrayLength(data); jbyte *ptr = _env->GetByteArrayElements(data, NULL); rsScriptGetVarV((RsContext)con, (RsScript)script, slot, ptr, len); - _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); + _env->ReleaseByteArrayElements(data, ptr, 0); } static void diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 5089b9de28a8..a6f24428dd93 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -42,6 +42,15 @@ typedef enum Command { } Command; /* + * Pseudolocalization methods + */ +typedef enum PseudolocalizationMethod { + NO_PSEUDOLOCALIZATION = 0, + PSEUDO_ACCENTED, + PSEUDO_BIDI, +} PseudolocalizationMethod; + +/* * Bundle of goodies, including everything specified on the command line. */ class Bundle { @@ -50,12 +59,12 @@ public: : mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false), mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false), mUpdate(false), mExtending(false), - mRequireLocalization(false), mPseudolocalize(false), + mRequireLocalization(false), mPseudolocalize(NO_PSEUDOLOCALIZATION), mWantUTF16(false), mValues(false), mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), mAutoAddOverlay(false), mGenDependencies(false), - mAssetSourceDir(NULL), + mAssetSourceDir(NULL), mCrunchedOutputDir(NULL), mProguardFile(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), @@ -94,8 +103,8 @@ public: void setExtending(bool val) { mExtending = val; } bool getRequireLocalization(void) const { return mRequireLocalization; } void setRequireLocalization(bool val) { mRequireLocalization = val; } - bool getPseudolocalize(void) const { return mPseudolocalize; } - void setPseudolocalize(bool val) { mPseudolocalize = val; } + short getPseudolocalize(void) const { return mPseudolocalize; } + void setPseudolocalize(short val) { mPseudolocalize = val; } void setWantUTF16(bool val) { mWantUTF16 = val; } bool getValues(void) const { return mValues; } void setValues(bool val) { mValues = val; } @@ -250,7 +259,7 @@ private: bool mUpdate; bool mExtending; bool mRequireLocalization; - bool mPseudolocalize; + short mPseudolocalize; bool mWantUTF16; bool mValues; int mCompressionMethod; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index c7cce96cf401..f7de5581527b 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -1885,14 +1885,17 @@ int doPackage(Bundle* bundle) FILE* fp; String8 dependencyFile; - // -c zz_ZZ means do pseudolocalization + // -c en_XA or/and ar_XB means do pseudolocalization ResourceFilter filter; err = filter.parse(bundle->getConfigurations()); if (err != NO_ERROR) { goto bail; } if (filter.containsPseudo()) { - bundle->setPseudolocalize(true); + bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED); + } + if (filter.containsPseudoBidi()) { + bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI); } N = bundle->getFileSpecCount(); diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp index e8a2be4a846e..8ca852e0813f 100644 --- a/tools/aapt/ResourceFilter.cpp +++ b/tools/aapt/ResourceFilter.cpp @@ -24,8 +24,10 @@ ResourceFilter::parse(const char* arg) String8 part(p, q-p); - if (part == "zz_ZZ") { - mContainsPseudo = true; + if (part == "en_XA") { + mContainsPseudoAccented = true; + } else if (part == "ar_XB") { + mContainsPseudoBidi = true; } int axis; AxisValue value; diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h index 0d127ba352c9..c57770e3f187 100644 --- a/tools/aapt/ResourceFilter.h +++ b/tools/aapt/ResourceFilter.h @@ -16,19 +16,22 @@ class ResourceFilter { public: - ResourceFilter() : mData(), mContainsPseudo(false) {} + ResourceFilter() : mData(), mContainsPseudoAccented(false), + mContainsPseudoBidi(false) {} status_t parse(const char* arg); bool isEmpty() const; bool match(int axis, const ResTable_config& config) const; bool match(const ResTable_config& config) const; const SortedVector<AxisValue>* configsForAxis(int axis) const; - inline bool containsPseudo() const { return mContainsPseudo; } + inline bool containsPseudo() const { return mContainsPseudoAccented; } + inline bool containsPseudoBidi() const { return mContainsPseudoBidi; } private: bool match(int axis, const AxisValue& value) const; KeyedVector<int,SortedVector<AxisValue> > mData; - bool mContainsPseudo; + bool mContainsPseudoAccented; + bool mContainsPseudoBidi; }; #endif diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 0b1f98536dda..26b5bd6401e8 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -25,7 +25,7 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, if (root == NULL) { return UNKNOWN_ERROR; } - + return compileXmlFile(assets, root, target, table, options); } @@ -577,13 +577,13 @@ status_t parseAndAddBag(Bundle* bundle, int32_t curFormat, bool isFormatted, const String16& product, - bool pseudolocalize, + PseudolocalizationMethod pseudolocalize, const bool overwrite, ResourceTable* outTable) { status_t err; const String16 item16("item"); - + String16 str; Vector<StringPool::entry_style_span> spans; err = parseStyledString(bundle, in->getPrintableSource().string(), @@ -672,7 +672,7 @@ status_t parseAndAddEntry(Bundle* bundle, int32_t curFormat, bool isFormatted, const String16& product, - bool pseudolocalize, + PseudolocalizationMethod pseudolocalize, const bool overwrite, KeyedVector<type_ident_pair_t, bool>* skippedResourceNames, ResourceTable* outTable) @@ -854,10 +854,16 @@ status_t compileResourceFile(Bundle* bundle, ResTable_config curParams(defParams); ResTable_config pseudoParams(curParams); - pseudoParams.language[0] = 'z'; - pseudoParams.language[1] = 'z'; - pseudoParams.country[0] = 'Z'; - pseudoParams.country[1] = 'Z'; + pseudoParams.language[0] = 'e'; + pseudoParams.language[1] = 'n'; + pseudoParams.country[0] = 'X'; + pseudoParams.country[1] = 'A'; + + ResTable_config pseudoBidiParams(curParams); + pseudoBidiParams.language[0] = 'a'; + pseudoBidiParams.language[1] = 'r'; + pseudoBidiParams.country[0] = 'X'; + pseudoBidiParams.country[1] = 'B'; while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::START_TAG) { @@ -1334,6 +1340,7 @@ status_t compileResourceFile(Bundle* bundle, name, locale, SourcePos(in->getPrintableSource(), block.getLineNumber())); + curIsPseudolocalizable = fileIsTranslatable; } if (formatted == false16) { @@ -1389,6 +1396,7 @@ status_t compileResourceFile(Bundle* bundle, curTag = &plurals16; curType = plurals16; curIsBag = true; + curIsPseudolocalizable = fileIsTranslatable; } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) { curTag = &array16; curType = array16; @@ -1410,25 +1418,23 @@ status_t compileResourceFile(Bundle* bundle, } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) { // Check whether these strings need valid formats. // (simplified form of what string16 does above) + bool isTranslatable = false; size_t n = block.getAttributeCount(); // Pseudolocalizable by default, unless this string array isn't // translatable. - curIsPseudolocalizable = true; for (size_t i = 0; i < n; i++) { size_t length; const uint16_t* attr = block.getAttributeName(i, &length); - if (strcmp16(attr, translatable16.string()) == 0) { + if (strcmp16(attr, formatted16.string()) == 0) { const uint16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { - curIsPseudolocalizable = false; + curIsFormatted = false; } - } - - if (strcmp16(attr, formatted16.string()) == 0) { + } else if (strcmp16(attr, translatable16.string()) == 0) { const uint16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { - curIsFormatted = false; + isTranslatable = false; } } } @@ -1438,6 +1444,7 @@ status_t compileResourceFile(Bundle* bundle, curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; curIsBag = true; curIsBagReplaceOnOverwrite = true; + curIsPseudolocalizable = isTranslatable && fileIsTranslatable; } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) { curTag = &integer_array16; curType = array16; @@ -1559,19 +1566,29 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, curIsFormatted, - product, false, overwrite, outTable); + product, NO_PSEUDOLOCALIZATION, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { + && bundle->getPseudolocalize() > 0) { // pseudolocalize here -#if 1 - block.setPosition(parserPosition); - err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, - curType, ident, parentIdent, itemIdent, curFormat, - curIsFormatted, product, true, overwrite, outTable); -#endif + if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) == + PSEUDO_ACCENTED) { + block.setPosition(parserPosition); + err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, + curType, ident, parentIdent, itemIdent, curFormat, + curIsFormatted, product, PSEUDO_ACCENTED, + overwrite, outTable); + } + if ((PSEUDO_BIDI & bundle->getPseudolocalize()) == + PSEUDO_BIDI) { + block.setPosition(parserPosition); + err = parseAndAddBag(bundle, in, &block, pseudoBidiParams, myPackage, + curType, ident, parentIdent, itemIdent, curFormat, + curIsFormatted, product, PSEUDO_BIDI, + overwrite, outTable); + } } - } + } if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -1592,20 +1609,31 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, curIsFormatted, - product, false, overwrite, &skippedResourceNames, outTable); + product, NO_PSEUDOLOCALIZATION, overwrite, &skippedResourceNames, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; } else if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { + && bundle->getPseudolocalize() > 0) { // pseudolocalize here - block.setPosition(parserPosition); - err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, - curIsFormatted, product, - true, overwrite, &skippedResourceNames, outTable); + if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) == + PSEUDO_ACCENTED) { + block.setPosition(parserPosition); + err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, + ident, *curTag, curIsStyled, curFormat, + curIsFormatted, product, + PSEUDO_ACCENTED, overwrite, &skippedResourceNames, outTable); + } + if ((PSEUDO_BIDI & bundle->getPseudolocalize()) == + PSEUDO_BIDI) { + block.setPosition(parserPosition); + err = parseAndAddEntry(bundle, in, &block, pseudoBidiParams, + myPackage, curType, ident, *curTag, curIsStyled, curFormat, + curIsFormatted, product, + PSEUDO_BIDI, overwrite, &skippedResourceNames, outTable); + } if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -2636,8 +2664,8 @@ ResourceTable::validateLocalizations(void) continue; } - // don't bother with the pseudolocale "zz_ZZ" - if (config != "zz_ZZ") { + // don't bother with the pseudolocale "en_XA" or "ar_XB" + if (config != "en_XA" && config != "ar_XB") { if (configSrcMap.find(config) == configSrcMap.end()) { // okay, no specific localization found. it's possible that we are // requiring a specific regional localization [e.g. de_DE] but there is an diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index a663ad58fc55..607d419b2971 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -187,7 +187,7 @@ status_t parseStyledString(Bundle* bundle, String16* outString, Vector<StringPool::entry_style_span>* outSpans, bool isFormatted, - bool pseudolocalize) + PseudolocalizationMethod pseudolocalize) { Vector<StringPool::entry_style_span> spanStack; String16 curString; @@ -198,21 +198,30 @@ status_t parseStyledString(Bundle* bundle, size_t len; ResXMLTree::event_code_t code; + // Bracketing if pseudolocalization accented method specified. + if (pseudolocalize == PSEUDO_ACCENTED) { + curString.append(String16(String8("["))); + } while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::TEXT) { String16 text(inXml->getText(&len)); if (firstTime && text.size() > 0) { firstTime = false; if (text.string()[0] == '@') { // If this is a resource reference, don't do the pseudoloc. - pseudolocalize = false; + pseudolocalize = NO_PSEUDOLOCALIZATION; } } - if (xliffDepth == 0 && pseudolocalize) { - std::string orig(String8(text).string()); - std::string pseudo = pseudolocalize_string(orig); - curString.append(String16(String8(pseudo.c_str()))); + if (xliffDepth == 0 && pseudolocalize > 0) { + String16 pseudo; + if (pseudolocalize == PSEUDO_ACCENTED) { + pseudo = pseudolocalize_string(text); + } else if (pseudolocalize == PSEUDO_BIDI) { + pseudo = pseudobidi_string(text); + } else { + pseudo = text; + } + curString.append(pseudo); } else { if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) { return UNKNOWN_ERROR; @@ -352,6 +361,25 @@ moveon: } } + // Bracketing if pseudolocalization accented method specified. + if (pseudolocalize == PSEUDO_ACCENTED) { + const char16_t* str = outString->string(); + const char16_t* p = str; + const char16_t* e = p + outString->size(); + int words_cnt = 0; + while (p < e) { + if (isspace(*p)) { + words_cnt++; + } + p++; + } + unsigned int length = words_cnt > 3 ? outString->size() : + outString->size() / 2; + curString.append(String16(String8(" "))); + curString.append(pseudo_generate_expansion(length)); + curString.append(String16(String8("]"))); + } + if (code == ResXMLTree::BAD_DOCUMENT) { SourcePos(String8(fileName), inXml->getLineNumber()).error( "Error parsing XML\n"); diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h index 05624b745176..ccbf9f403116 100644 --- a/tools/aapt/XMLNode.h +++ b/tools/aapt/XMLNode.h @@ -26,7 +26,7 @@ status_t parseStyledString(Bundle* bundle, String16* outString, Vector<StringPool::entry_style_span>* outSpans, bool isFormatted, - bool isPseudolocalizable); + PseudolocalizationMethod isPseudolocalizable); void printXMLBlock(ResXMLTree* block); diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp index 9e50c5ac5eb1..60aa2b2d3e3d 100644 --- a/tools/aapt/pseudolocalize.cpp +++ b/tools/aapt/pseudolocalize.cpp @@ -2,89 +2,155 @@ using namespace std; +// String basis to generate expansion +static const String16 k_expansion_string = String16("one two three " + "four five six seven eight nine ten eleven twelve thirteen " + "fourteen fiveteen sixteen seventeen nineteen twenty"); + +// Special unicode characters to override directionality of the words +static const String16 k_rlm = String16("\xe2\x80\x8f"); +static const String16 k_rlo = String16("\xE2\x80\xae"); +static const String16 k_pdf = String16("\xE2\x80\xac"); + +// Placeholder marks +static const String16 k_placeholder_open = String16("\xc2\xbb"); +static const String16 k_placeholder_close = String16("\xc2\xab"); + static const char* -pseudolocalize_char(char c) +pseudolocalize_char(const char16_t c) { switch (c) { - case 'a': return "\xc4\x83"; - case 'b': return "\xcf\x84"; - case 'c': return "\xc4\x8b"; - case 'd': return "\xc4\x8f"; - case 'e': return "\xc4\x99"; + case 'a': return "\xc3\xa5"; + case 'b': return "\xc9\x93"; + case 'c': return "\xc3\xa7"; + case 'd': return "\xc3\xb0"; + case 'e': return "\xc3\xa9"; case 'f': return "\xc6\x92"; case 'g': return "\xc4\x9d"; - case 'h': return "\xd1\x9b"; - case 'i': return "\xcf\x8a"; + case 'h': return "\xc4\xa5"; + case 'i': return "\xc3\xae"; case 'j': return "\xc4\xb5"; - case 'k': return "\xc4\xb8"; - case 'l': return "\xc4\xba"; + case 'k': return "\xc4\xb7"; + case 'l': return "\xc4\xbc"; case 'm': return "\xe1\xb8\xbf"; - case 'n': return "\xd0\xb8"; - case 'o': return "\xcf\x8c"; - case 'p': return "\xcf\x81"; + case 'n': return "\xc3\xb1"; + case 'o': return "\xc3\xb6"; + case 'p': return "\xc3\xbe"; case 'q': return "\x51"; - case 'r': return "\xd2\x91"; + case 'r': return "\xc5\x95"; case 's': return "\xc5\xa1"; - case 't': return "\xd1\x82"; - case 'u': return "\xce\xb0"; + case 't': return "\xc5\xa3"; + case 'u': return "\xc3\xbb"; case 'v': return "\x56"; - case 'w': return "\xe1\xba\x85"; + case 'w': return "\xc5\xb5"; case 'x': return "\xd1\x85"; - case 'y': return "\xe1\xbb\xb3"; - case 'z': return "\xc5\xba"; + case 'y': return "\xc3\xbd"; + case 'z': return "\xc5\xbe"; case 'A': return "\xc3\x85"; case 'B': return "\xce\xb2"; - case 'C': return "\xc4\x88"; - case 'D': return "\xc4\x90"; - case 'E': return "\xd0\x84"; - case 'F': return "\xce\x93"; - case 'G': return "\xc4\x9e"; - case 'H': return "\xc4\xa6"; - case 'I': return "\xd0\x87"; - case 'J': return "\xc4\xb5"; + case 'C': return "\xc3\x87"; + case 'D': return "\xc3\x90"; + case 'E': return "\xc3\x89"; + case 'G': return "\xc4\x9c"; + case 'H': return "\xc4\xa4"; + case 'I': return "\xc3\x8e"; + case 'J': return "\xc4\xb4"; case 'K': return "\xc4\xb6"; - case 'L': return "\xc5\x81"; + case 'L': return "\xc4\xbb"; case 'M': return "\xe1\xb8\xbe"; - case 'N': return "\xc5\x83"; - case 'O': return "\xce\x98"; - case 'P': return "\xcf\x81"; + case 'N': return "\xc3\x91"; + case 'O': return "\xc3\x96"; + case 'P': return "\xc3\x9e"; case 'Q': return "\x71"; - case 'R': return "\xd0\xaf"; - case 'S': return "\xc8\x98"; - case 'T': return "\xc5\xa6"; - case 'U': return "\xc5\xa8"; + case 'R': return "\xc5\x94"; + case 'S': return "\xc5\xa0"; + case 'T': return "\xc5\xa2"; + case 'U': return "\xc3\x9b"; case 'V': return "\xce\xbd"; - case 'W': return "\xe1\xba\x84"; + case 'W': return "\xc5\xb4"; case 'X': return "\xc3\x97"; - case 'Y': return "\xc2\xa5"; + case 'Y': return "\xc3\x9d"; case 'Z': return "\xc5\xbd"; + case '!': return "\xc2\xa1"; + case '?': return "\xc2\xbf"; + case '$': return "\xe2\x82\xac"; default: return NULL; } } +static bool +is_possible_normal_placeholder_end(const char16_t c) { + switch (c) { + case 's': return true; + case 'S': return true; + case 'c': return true; + case 'C': return true; + case 'd': return true; + case 'o': return true; + case 'x': return true; + case 'X': return true; + case 'f': return true; + case 'e': return true; + case 'E': return true; + case 'g': return true; + case 'G': return true; + case 'a': return true; + case 'A': return true; + case 'b': return true; + case 'B': return true; + case 'h': return true; + case 'H': return true; + case '%': return true; + case 'n': return true; + default: return false; + } +} + +String16 +pseudo_generate_expansion(const unsigned int length) { + String16 result = k_expansion_string; + const char16_t* s = result.string(); + if (result.size() < length) { + result += String16(" "); + result += pseudo_generate_expansion(length - result.size()); + } else { + int ext = 0; + // Should contain only whole words, so looking for a space + for (unsigned int i = length + 1; i < result.size(); ++i) { + ++ext; + if (s[i] == ' ') { + break; + } + } + result.remove(length + ext, 0); + } + return result; +} + /** * Converts characters so they look like they've been localized. * * Note: This leaves escape sequences untouched so they can later be * processed by ResTable::collectString in the normal way. */ -string -pseudolocalize_string(const string& source) +String16 +pseudolocalize_string(const String16& source) { - const char* s = source.c_str(); - string result; - const size_t I = source.length(); + const char16_t* s = source.string(); + String16 result; + const size_t I = source.size(); for (size_t i=0; i<I; i++) { - char c = s[i]; + char16_t c = s[i]; if (c == '\\') { + // Escape syntax, no need to pseudolocalize if (i<I-1) { - result += '\\'; + result += String16("\\"); i++; c = s[i]; switch (c) { case 'u': // this one takes up 5 chars - result += string(s+i, 5); + result += String16(s+i, 5); i += 4; break; case 't': @@ -96,24 +162,107 @@ pseudolocalize_string(const string& source) case '\'': case '\\': default: - result += c; + result.append(&c, 1); break; } } else { - result += c; + result.append(&c, 1); + } + } else if (c == '%') { + // Placeholder syntax, no need to pseudolocalize + result += k_placeholder_open; + bool end = false; + result.append(&c, 1); + while (!end && i < I) { + ++i; + c = s[i]; + result.append(&c, 1); + if (is_possible_normal_placeholder_end(c)) { + end = true; + } else if (c == 't') { + ++i; + c = s[i]; + result.append(&c, 1); + end = true; + } + } + result += k_placeholder_close; + } else if (c == '<' || c == '&') { + // html syntax, no need to pseudolocalize + bool tag_closed = false; + while (!tag_closed && i < I) { + if (c == '&') { + String16 escape_text; + escape_text.append(&c, 1); + bool end = false; + size_t htmlCodePos = i; + while (!end && htmlCodePos < I) { + ++htmlCodePos; + c = s[htmlCodePos]; + escape_text.append(&c, 1); + // Valid html code + if (c == ';') { + end = true; + i = htmlCodePos; + } + // Wrong html code + else if (!((c == '#' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')))) { + end = true; + } + } + result += escape_text; + if (escape_text != String16("<")) { + tag_closed = true; + } + continue; + } + if (c == '>') { + tag_closed = true; + result.append(&c, 1); + continue; + } + result.append(&c, 1); + i++; + c = s[i]; } } else { + // This is a pure text that should be pseudolocalized const char* p = pseudolocalize_char(c); if (p != NULL) { - result += p; + result += String16(p); } else { - result += c; + result.append(&c, 1); } } } - - //printf("result=\'%s\'\n", result.c_str()); return result; } +String16 +pseudobidi_string(const String16& source) +{ + const char16_t* s = source.string(); + String16 result; + result += k_rlm; + result += k_rlo; + for (size_t i=0; i<source.size(); i++) { + char16_t c = s[i]; + switch(c) { + case ' ': result += k_pdf; + result += k_rlm; + result.append(&c, 1); + result += k_rlm; + result += k_rlo; + break; + default: result.append(&c, 1); + break; + } + } + result += k_pdf; + result += k_rlm; + return result; +} diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h index 94cb034ac5ea..e6ab18ef1747 100644 --- a/tools/aapt/pseudolocalize.h +++ b/tools/aapt/pseudolocalize.h @@ -1,9 +1,18 @@ #ifndef HOST_PSEUDOLOCALIZE_H #define HOST_PSEUDOLOCALIZE_H +#include "StringPool.h" + #include <string> -std::string pseudolocalize_string(const std::string& source); +String16 pseudolocalize_string(const String16& source); +// Surrounds every word in the sentance with specific characters that makes +// the word directionality RTL. +String16 pseudobidi_string(const String16& source); +// Generates expansion string based on the specified lenght. +// Generated string could not be shorter that length, but it could be slightly +// longer. +String16 pseudo_generate_expansion(const unsigned int length); #endif // HOST_PSEUDOLOCALIZE_H |