From b80e42f93ff26984c410da0235dd10f463e5722a Mon Sep 17 00:00:00 2001 From: Deepanshu Gupta Date: Thu, 31 Jul 2014 14:32:34 -0700 Subject: [PATCH] Replace more Locale methods. This change replaces some methods of java.util.Locale. Some of them were added in 1.7 and some are not present in the Desktop VM. Change-Id: Ifdf8451bb2acf55e01dce8b5e15c40c8160107cc --- .../layoutlib/bridge/android/AndroidLocale.java | 23 +++++ .../tools/layoutlib/create/AsmAnalyzer.java | 1 + .../create/ReplaceMethodCallsAdapter.java | 97 ++++++++++++++-------- 3 files changed, 86 insertions(+), 35 deletions(-) diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java index 607e62877580..ea5f1eabe552 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java @@ -33,4 +33,27 @@ public class AndroidLocale { public static String toLanguageTag(Locale locale) { return ULocale.forLocale(locale).toLanguageTag(); } + + public static String adjustLanguageCode(String languageCode) { + String adjusted = languageCode.toLowerCase(Locale.US); + // Map new language codes to the obsolete language + // codes so the correct resource bundles will be used. + if (languageCode.equals("he")) { + adjusted = "iw"; + } else if (languageCode.equals("id")) { + adjusted = "in"; + } else if (languageCode.equals("yi")) { + adjusted = "ji"; + } + + return adjusted; + } + + public static Locale forLanguageTag(String tag) { + return ULocale.forLanguageTag(tag).toLocale(); + } + + public static String getScript(Locale locale) { + return ULocale.forLocale(locale).getScript(); + } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java index e043d4d2572a..9a10f790cdc5 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java @@ -341,6 +341,7 @@ public class AsmAnalyzer { inOutKeepClasses.size(), deps.size()); for (ClassReader cr : temp.values()) { + visitor.setClassName(cr.getClassName()); cr.accept(visitor, 0 /* flags */); } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java index 94d5975347c8..9c6fbac1133e 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java @@ -19,11 +19,13 @@ package com.android.tools.layoutlib.create; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; /** @@ -42,45 +44,70 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { private static final List METHOD_REPLACERS = new ArrayList(2); + private static final String ANDROID_LOCALE_CLASS = + "com/android/layoutlib/bridge/android/AndroidLocale"; + + private static final String JAVA_LOCALE_CLASS = "java/util/Locale"; + private static final Type STRING = Type.getType(String.class); + // Static initialization block to initialize METHOD_REPLACERS. static { // Case 1: java.lang.System.arraycopy() METHOD_REPLACERS.add(new MethodReplacer() { @Override public boolean isNeeded(String owner, String name, String desc) { - return owner.equals("java/lang/System") && name.equals("arraycopy") && + return "java/lang/System".equals(owner) && "arraycopy".equals(name) && ARRAYCOPY_DESCRIPTORS.contains(desc); } @Override - public void replace(int opcode, String owner, String name, String desc, - int[] opcodeOut, String[] output) { - assert isNeeded(owner, name, desc) && output.length == 3 - && opcodeOut.length == 1; - opcodeOut[0] = opcode; - output[0] = owner; - output[1] = name; - output[2] = "(Ljava/lang/Object;ILjava/lang/Object;II)V"; + public void replace(int[] opcode, String[] methodInformation) { + assert methodInformation.length == 3 && isNeeded(methodInformation[0], methodInformation[1], methodInformation[2]) + && opcode.length == 1; + methodInformation[2] = "(Ljava/lang/Object;ILjava/lang/Object;II)V"; } }); - // Case 2: java.util.Locale.toLanguageTag() + // Case 2: java.util.Locale.toLanguageTag() and java.util.Locale.getScript() METHOD_REPLACERS.add(new MethodReplacer() { + + String LOCALE_TO_STRING = Type.getMethodDescriptor(STRING, Type.getType(Locale.class)); + + @Override + public boolean isNeeded(String owner, String name, String desc) { + return JAVA_LOCALE_CLASS.equals(owner) && "()Ljava/lang/String;".equals(desc) && + ("toLanguageTag".equals(name) || "getScript".equals(name)); + } + + @Override + public void replace(int[] opcode, String[] methodInformation) { + assert methodInformation.length == 3 && isNeeded(methodInformation[0], methodInformation[1], methodInformation[2]) + && opcode.length == 1; + opcode[0] = Opcodes.INVOKESTATIC; + methodInformation[0] = ANDROID_LOCALE_CLASS; + methodInformation[2] = LOCALE_TO_STRING; + } + }); + + // Case 3: java.util.Locale.adjustLanguageCode() or java.util.Locale.forLanguageTag() + METHOD_REPLACERS.add(new MethodReplacer() { + + private final String STRING_TO_STRING = Type.getMethodDescriptor(STRING, STRING); + private final String STRING_TO_LOCALE = Type.getMethodDescriptor( + Type.getType(Locale.class), STRING); + @Override public boolean isNeeded(String owner, String name, String desc) { - return owner.equals("java/util/Locale") && name.equals("toLanguageTag") && - "()Ljava/lang/String;".equals(desc); + return JAVA_LOCALE_CLASS.equals(owner) && + ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) || + "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE)); } @Override - public void replace(int opcode, String owner, String name, String desc, - int[] opcodeOut, String[] output) { - assert isNeeded(owner, name, desc) && output.length == 3 - && opcodeOut.length == 1; - opcodeOut[0] = Opcodes.INVOKESTATIC; - output[0] = "com/android/layoutlib/bridge/android/AndroidLocale"; - output[1] = name; - output[2] = "(Ljava/util/Locale;)Ljava/lang/String;"; + public void replace(int[] opcode, String[] methodInformation) { + assert methodInformation.length == 3 && isNeeded(methodInformation[0], methodInformation[1], methodInformation[2]) + && opcode.length == 1; + methodInformation[0] = ANDROID_LOCALE_CLASS; } }); } @@ -112,16 +139,15 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { - // Check if method is a specialized version of java.lang.System.arrayCopy for (MethodReplacer replacer : METHOD_REPLACERS) { if (replacer.isNeeded(owner, name, desc)) { - String[] output = new String[3]; - int[] opcodeOut = new int[1]; - replacer.replace(opcode, owner, name, desc, opcodeOut, output); + String[] methodInformation = {owner, name, desc}; + int[] opcodeOut = {opcode}; + replacer.replace(opcodeOut, methodInformation); opcode = opcodeOut[0]; - owner = output[0]; - name = output[1]; - desc = output[2]; + owner = methodInformation[0]; + name = methodInformation[1]; + desc = methodInformation[2]; break; } } @@ -133,14 +159,15 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { public boolean isNeeded(String owner, String name, String desc); /** - * This method must update the values of the output arrays with the new values of method - * attributes - opcode, owner, name and desc. - * @param opcodeOut An array that will contain the new value of the opcode. The size of - * the array must be 1. - * @param output An array that will contain the new values of the owner, name and desc in - * that order. The size of the array must be 3. + * This method must update the arrays with the new values of the method attributes - + * opcode, owner, name and desc. + * @param opcode This array should contain the original value of the opcode. The value is + * modified by the method if needed. The size of the array must be 1. + * + * @param methodInformation This array should contain the original values of the method + * attributes - owner, name and desc in that order. The values + * may be modified as needed. The size of the array must be 3. */ - public void replace(int opcode, String owner, String name, String desc, int[] opcodeOut, - String[] output); + public void replace(int[] opcode, String[] methodInformation); } } -- 2.11.0