summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/AaptAssets.cpp5
-rw-r--r--tools/aapt/Android.mk4
-rw-r--r--tools/aapt/Command.cpp31
-rw-r--r--tools/aapt/Resource.cpp114
-rw-r--r--tools/aidl/aidl.cpp78
-rw-r--r--tools/aidl/aidl_language.h4
-rw-r--r--tools/aidl/aidl_language_l.l4
-rw-r--r--tools/aidl/aidl_language_y.y45
-rw-r--r--tools/aidl/generate_java_binder.cpp5
-rw-r--r--tools/layoutlib/bridge/.classpath1
-rw-r--r--tools/layoutlib/bridge/Android.mk1
-rw-r--r--tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_charge_anim100.pngbin0 -> 1040 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.pngbin1195 -> 2436 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.pngbin0 -> 904 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.pngbin0 -> 533 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.pngbin0 -> 617 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.pngbin0 -> 423 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.pngbin0 -> 1250 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.pngbin0 -> 552 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_charge_anim100.pngbin0 -> 762 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.pngbin885 -> 1430 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/status_bar.xml8
-rw-r--r--tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_charge_anim100.pngbin0 -> 1332 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_wifi_signal_4_fully.pngbin0 -> 3485 bytes
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java215
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java29
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java110
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java172
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/os/Looper_Accessor.java20
-rw-r--r--tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java31
-rw-r--r--tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java61
-rw-r--r--tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java59
-rw-r--r--tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java2
-rw-r--r--tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java29
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java22
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java34
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java32
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java9
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java26
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java13
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java22
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java23
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java25
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java)137
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java74
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java24
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java50
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java20
-rw-r--r--tools/layoutlib/create/.classpath4
-rw-r--r--tools/layoutlib/create/README.txt55
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java418
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java25
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java22
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java34
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java7
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java18
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java49
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java386
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java31
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/java/Charsets.java133
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/java/IntegralToString.java537
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/java/UnsafeByteSequence.java81
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java11
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java215
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java14
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/JavaClass.java22
-rw-r--r--tools/layoutlib/create/tests/data/mock_android.jarbin9075 -> 9096 bytes
-rw-r--r--tools/layoutlib/create/tests/data/mock_android.jardesc18
-rw-r--r--tools/layoutlib/create/tests/mock_data/java/lang/JavaClass.java22
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/dummy/InnerTest.java (renamed from tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java)7
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/view/View.java (renamed from tools/layoutlib/create/tests/mock_android/view/View.java)4
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/view/ViewGroup.java (renamed from tools/layoutlib/create/tests/mock_android/view/ViewGroup.java)0
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java (renamed from tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java)0
-rw-r--r--tools/layoutlib/create/tests/mock_data/mock_android/widget/TableLayout.java (renamed from tools/layoutlib/create/tests/mock_android/widget/TableLayout.java)0
-rw-r--r--tools/obbtool/Android.mk3
-rw-r--r--tools/preload/Policy.java1
-rw-r--r--tools/preload/Record.java10
-rw-r--r--tools/validatekeymaps/Android.mk3
82 files changed, 2733 insertions, 957 deletions
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 5b71adc81cbe..2149190b10be 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1185,6 +1185,11 @@ bool AaptGroupEntry::getDensityName(const char* name,
return true;
}
+ if (strcmp(name, "xxxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+ return true;
+ }
+
char* c = (char*)name;
while (*c >= '0' && *c <= '9') {
c++;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 5b8866901e03..9b1658ac6de9 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -39,14 +39,14 @@ LOCAL_C_INCLUDES += external/libpng
LOCAL_C_INCLUDES += external/zlib
LOCAL_C_INCLUDES += build/libs/host/include
-#LOCAL_WHOLE_STATIC_LIBRARIES :=
LOCAL_STATIC_LIBRARIES := \
libhost \
libandroidfw \
libutils \
libcutils \
libexpat \
- libpng
+ libpng \
+ liblog
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt -ldl -lpthread
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f7083a9e9e86..cadac02f1e04 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -592,6 +592,10 @@ int doDump(Bundle* bundle)
goto bail;
}
printf("uses-permission: %s\n", name.string());
+ int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+ if (!req) {
+ printf("optional-permission: %s\n", name.string());
+ }
}
}
} else if (strcmp("badging", option) == 0) {
@@ -1033,6 +1037,10 @@ int doDump(Bundle* bundle)
hasWriteCallLogPermission = true;
}
printf("uses-permission:'%s'\n", name.string());
+ int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+ if (!req) {
+ printf("optional-permission:'%s'\n", name.string());
+ }
} else {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
@@ -1283,7 +1291,7 @@ int doDump(Bundle* bundle)
// network location feature, we infer that it meant to
printf("uses-feature:'android.hardware.location.network'\n");
printf("uses-implied-feature:'android.hardware.location.network'," \
- "'requested android.permission.ACCESS_COURSE_LOCATION permission'\n");
+ "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n");
}
// Bluetooth-related compatibility logic
@@ -1840,6 +1848,27 @@ int doCrunch(Bundle* bundle)
return NO_ERROR;
}
+/*
+ * Do PNG Crunching on a single flag
+ * -i points to a single png file
+ * -o points to a single png output file
+ */
+int doSingleCrunch(Bundle* bundle)
+{
+ fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
+ fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
+
+ String8 input(bundle->getSingleCrunchInputFile());
+ String8 output(bundle->getSingleCrunchOutputFile());
+
+ if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
+ // we can't return the status_t as it gets truncate to the lower 8 bits.
+ return 42;
+ }
+
+ return NO_ERROR;
+}
+
char CONSOLE_DATA[2925] = {
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 77168f948640..6168bbdc0655 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1568,11 +1568,37 @@ static const char whitespace[] =
return whitespace + sizeof(whitespace) - 1 - indent*4;
}
-static status_t fixupSymbol(String16* inoutSymbol)
-{
- inoutSymbol->replaceAll('.', '_');
- inoutSymbol->replaceAll(':', '_');
- return NO_ERROR;
+static String8 flattenSymbol(const String8& symbol) {
+ String8 result(symbol);
+ ssize_t first;
+ if ((first = symbol.find(":", 0)) >= 0
+ || (first = symbol.find(".", 0)) >= 0) {
+ size_t size = symbol.size();
+ char* buf = result.lockBuffer(size);
+ for (size_t i = first; i < size; i++) {
+ if (buf[i] == ':' || buf[i] == '.') {
+ buf[i] = '_';
+ }
+ }
+ result.unlockBuffer(size);
+ }
+ return result;
+}
+
+static String8 getSymbolPackage(const String8& symbol, const sp<AaptAssets>& assets, bool pub) {
+ ssize_t colon = symbol.find(":", 0);
+ if (colon >= 0) {
+ return String8(symbol.string(), colon);
+ }
+ return pub ? assets->getPackage() : assets->getSymbolsPrivatePackage();
+}
+
+static String8 getSymbolName(const String8& symbol) {
+ ssize_t colon = symbol.find(":", 0);
+ if (colon >= 0) {
+ return String8(symbol.string() + colon + 1);
+ }
+ return symbol;
}
static String16 getAttributeComment(const sp<AaptAssets>& assets,
@@ -1616,12 +1642,8 @@ static status_t writeLayoutClasses(
size_t N = symbols->getNestedSymbols().size();
for (i=0; i<N; i++) {
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
- String16 nclassName16(symbols->getNestedSymbols().keyAt(i));
- String8 realClassName(nclassName16);
- if (fixupSymbol(&nclassName16) != NO_ERROR) {
- hasErrors = true;
- }
- String8 nclassName(nclassName16);
+ String8 realClassName(symbols->getNestedSymbols().keyAt(i));
+ String8 nclassName(flattenSymbol(realClassName));
SortedVector<uint32_t> idents;
Vector<uint32_t> origOrder;
@@ -1711,13 +1733,11 @@ static status_t writeLayoutClasses(
}
comment = String16(comment.string(), p-comment.string());
}
- String16 name(name8);
- fixupSymbol(&name);
fprintf(fp, "%s <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n",
indentStr, nclassName.string(),
- String8(name).string(),
- assets->getPackage().string(),
- String8(name).string(),
+ flattenSymbol(name8).string(),
+ getSymbolPackage(name8, assets, true).string(),
+ getSymbolName(name8).string(),
String8(comment).string());
}
}
@@ -1731,11 +1751,9 @@ static status_t writeLayoutClasses(
if (!publicFlags.itemAt(a) && !includePrivate) {
continue;
}
- String16 name(sym.name);
- fixupSymbol(&name);
fprintf(fp, "%s @see #%s_%s\n",
indentStr, nclassName.string(),
- String8(name).string());
+ flattenSymbol(sym.name).string());
}
}
fprintf(fp, "%s */\n", getIndentSpace(indent));
@@ -1778,11 +1796,7 @@ static status_t writeLayoutClasses(
} else {
getAttributeComment(assets, name8, &typeComment);
}
- String16 name(name8);
- if (fixupSymbol(&name) != NO_ERROR) {
- hasErrors = true;
- }
-
+
uint32_t typeSpecFlags = 0;
String16 name16(sym.name);
assets->getIncludedResources().identifierForName(
@@ -1808,9 +1822,8 @@ static status_t writeLayoutClasses(
"%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
"%s attribute's value can be found in the {@link #%s} array.\n",
indentStr,
- pub ? assets->getPackage().string()
- : assets->getSymbolsPrivatePackage().string(),
- String8(name).string(),
+ getSymbolPackage(name8, assets, pub).string(),
+ getSymbolName(name8).string(),
indentStr, nclassName.string());
}
if (typeComment.size() > 0) {
@@ -1823,18 +1836,19 @@ static status_t writeLayoutClasses(
if (comment.size() > 0) {
if (pub) {
fprintf(fp,
- "%s <p>This corresponds to the global attribute"
+ "%s <p>This corresponds to the global attribute\n"
"%s resource symbol {@link %s.R.attr#%s}.\n",
indentStr, indentStr,
- assets->getPackage().string(),
- String8(name).string());
+ getSymbolPackage(name8, assets, true).string(),
+ getSymbolName(name8).string());
} else {
fprintf(fp,
"%s <p>This is a private symbol.\n", indentStr);
}
}
fprintf(fp, "%s @attr name %s:%s\n", indentStr,
- "android", String8(name).string());
+ getSymbolPackage(name8, assets, pub).string(),
+ getSymbolName(name8).string());
fprintf(fp, "%s*/\n", indentStr);
if (deprecated) {
fprintf(fp, "%s@Deprecated\n", indentStr);
@@ -1842,7 +1856,7 @@ static status_t writeLayoutClasses(
fprintf(fp,
"%spublic static final int %s_%s = %d;\n",
indentStr, nclassName.string(),
- String8(name).string(), (int)pos);
+ flattenSymbol(name8).string(), (int)pos);
}
}
}
@@ -1865,12 +1879,8 @@ static status_t writeTextLayoutClasses(
size_t N = symbols->getNestedSymbols().size();
for (i=0; i<N; i++) {
sp<AaptSymbols> nsymbols = symbols->getNestedSymbols().valueAt(i);
- String16 nclassName16(symbols->getNestedSymbols().keyAt(i));
- String8 realClassName(nclassName16);
- if (fixupSymbol(&nclassName16) != NO_ERROR) {
- hasErrors = true;
- }
- String8 nclassName(nclassName16);
+ String8 realClassName(symbols->getNestedSymbols().keyAt(i));
+ String8 nclassName(flattenSymbol(realClassName));
SortedVector<uint32_t> idents;
Vector<uint32_t> origOrder;
@@ -1930,10 +1940,6 @@ static status_t writeTextLayoutClasses(
} else {
getAttributeComment(assets, name8, &typeComment);
}
- String16 name(name8);
- if (fixupSymbol(&name) != NO_ERROR) {
- hasErrors = true;
- }
uint32_t typeSpecFlags = 0;
String16 name16(sym.name);
@@ -1948,7 +1954,7 @@ static status_t writeTextLayoutClasses(
fprintf(fp,
"int styleable %s_%s %d\n",
nclassName.string(),
- String8(name).string(), (int)pos);
+ flattenSymbol(name8).string(), (int)pos);
}
}
}
@@ -1982,10 +1988,7 @@ static status_t writeSymbolClass(
if (!assets->isJavaSymbol(sym, includePrivate)) {
continue;
}
- String16 name(sym.name);
- if (fixupSymbol(&name) != NO_ERROR) {
- return UNKNOWN_ERROR;
- }
+ String8 name8(sym.name);
String16 comment(sym.comment);
bool haveComment = false;
bool deprecated = false;
@@ -2026,7 +2029,7 @@ static status_t writeSymbolClass(
}
fprintf(fp, id_format,
getIndentSpace(indent),
- String8(name).string(), (int)sym.int32Val);
+ flattenSymbol(name8).string(), (int)sym.int32Val);
}
for (i=0; i<N; i++) {
@@ -2037,10 +2040,7 @@ static status_t writeSymbolClass(
if (!assets->isJavaSymbol(sym, includePrivate)) {
continue;
}
- String16 name(sym.name);
- if (fixupSymbol(&name) != NO_ERROR) {
- return UNKNOWN_ERROR;
- }
+ String8 name8(sym.name);
String16 comment(sym.comment);
bool deprecated = false;
if (comment.size() > 0) {
@@ -2063,7 +2063,7 @@ static status_t writeSymbolClass(
}
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
getIndentSpace(indent),
- String8(name).string(), sym.stringVal.string());
+ flattenSymbol(name8).string(), sym.stringVal.string());
}
sp<AaptSymbols> styleableSymbols;
@@ -2112,14 +2112,10 @@ static status_t writeTextSymbolClass(
continue;
}
- String16 name(sym.name);
- if (fixupSymbol(&name) != NO_ERROR) {
- return UNKNOWN_ERROR;
- }
-
+ String8 name8(sym.name);
fprintf(fp, "int %s %s 0x%08x\n",
className.string(),
- String8(name).string(), (int)sym.int32Val);
+ flattenSymbol(name8).string(), (int)sym.int32Val);
}
N = symbols->getNestedSymbols().size();
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 072824690a2e..071a8d771605 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -23,6 +23,12 @@
# define O_BINARY 0
#endif
+// The following are gotten as the offset from the allowable id's between
+// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
+// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
+#define MIN_USER_SET_METHOD_ID 0
+#define MAX_USER_SET_METHOD_ID 16777214
+
using namespace std;
static void
@@ -847,6 +853,72 @@ parse_preprocessed_file(const string& filename)
return 0;
}
+static int
+check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
+{
+ // Check whether there are any methods with manually assigned id's and any that are not.
+ // Either all method id's must be manually assigned or all of them must not.
+ // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
+ set<int> usedIds;
+ interface_item_type* item = first_item;
+ bool hasUnassignedIds = false;
+ bool hasAssignedIds = false;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ method_type* method_item = (method_type*)item;
+ if (method_item->hasId) {
+ hasAssignedIds = true;
+ method_item->assigned_id = atoi(method_item->id.data);
+ // Ensure that the user set id is not duplicated.
+ if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
+ // We found a duplicate id, so throw an error.
+ fprintf(stderr,
+ "%s:%d Found duplicate method id (%d) for method: %s\n",
+ filename, method_item->id.lineno,
+ method_item->assigned_id, method_item->name.data);
+ return 1;
+ }
+ // Ensure that the user set id is within the appropriate limits
+ if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
+ method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
+ fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
+ filename, method_item->id.lineno,
+ method_item->assigned_id, method_item->name.data);
+ fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
+ MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
+ return 1;
+ }
+ usedIds.insert(method_item->assigned_id);
+ } else {
+ hasUnassignedIds = true;
+ }
+ if (hasAssignedIds && hasUnassignedIds) {
+ fprintf(stderr,
+ "%s: You must either assign id's to all methods or to none of them.\n",
+ filename);
+ return 1;
+ }
+ }
+ item = item->next;
+ }
+
+ // In the case that all methods have unassigned id's, set a unique id for them.
+ if (hasUnassignedIds) {
+ int newId = 0;
+ item = first_item;
+ while (item != NULL) {
+ if (item->item_type == METHOD_TYPE) {
+ method_type* method_item = (method_type*)item;
+ method_item->assigned_id = newId++;
+ }
+ item = item->next;
+ }
+ }
+
+ // success
+ return 0;
+}
+
// ==========================================================
static int
compile_aidl(Options& options)
@@ -937,6 +1009,12 @@ compile_aidl(Options& options)
bool onlyParcelable = false;
err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
+ // If this includes an interface definition, then assign method ids and validate.
+ if (!onlyParcelable) {
+ err |= check_and_assign_method_ids(options.inputFileName.c_str(),
+ ((interface_type*)mainDoc)->interface_items);
+ }
+
// after this, there shouldn't be any more errors because of the
// input.
if (err != 0 || mainDoc == NULL) {
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index f203dbb0869f..de1370c086f5 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -57,9 +57,13 @@ typedef struct method_type {
buffer_type open_paren_token;
arg_type* args;
buffer_type close_paren_token;
+ bool hasId;
+ buffer_type equals_token;
+ buffer_type id;
// XXX missing comments/copy text here
buffer_type semicolon_token;
buffer_type* comments_token; // points into this structure, DO NOT DELETE
+ int assigned_id;
} method_type;
enum {
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 7c5290cf8250..3d33e7a14913 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -36,6 +36,7 @@ static void do_package_statement(const char* importText);
identifier [_a-zA-Z][_a-zA-Z0-9\.]*
whitespace ([ \t\n\r]+)
brackets \[{whitespace}?\]
+idvalue (0|[1-9][0-9]*)
%%
@@ -77,6 +78,7 @@ brackets \[{whitespace}?\]
\( { SET_BUFFER('('); return '('; }
\) { SET_BUFFER(')'); return ')'; }
, { SET_BUFFER(','); return ','; }
+= { SET_BUFFER('='); return '='; }
/* keywords */
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
@@ -89,7 +91,7 @@ inout { SET_BUFFER(INOUT); return INOUT; }
oneway { SET_BUFFER(ONEWAY); return ONEWAY; }
{brackets}+ { SET_BUFFER(ARRAY); return ARRAY; }
-
+{idvalue} { SET_BUFFER(IDVALUE); return IDVALUE; }
{identifier} { SET_BUFFER(IDENTIFIER); return IDENTIFIER; }
{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\> {
SET_BUFFER(GENERIC); return GENERIC; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index cc04d151bc14..9b40d28ad598 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -15,6 +15,7 @@ static int count_brackets(const char*);
%token IMPORT
%token PACKAGE
%token IDENTIFIER
+%token IDVALUE
%token GENERIC
%token ARRAY
%token PARCELABLE
@@ -211,13 +212,16 @@ method_decl:
method_type *method = (method_type*)malloc(sizeof(method_type));
method->interface_item.item_type = METHOD_TYPE;
method->interface_item.next = NULL;
- method->type = $1.type;
method->oneway = false;
+ method->type = $1.type;
memset(&method->oneway_token, 0, sizeof(buffer_type));
method->name = $2.buffer;
method->open_paren_token = $3.buffer;
method->args = $4.arg;
method->close_paren_token = $5.buffer;
+ method->hasId = false;
+ memset(&method->equals_token, 0, sizeof(buffer_type));
+ memset(&method->id, 0, sizeof(buffer_type));
method->semicolon_token = $6.buffer;
method->comments_token = &method->type.type;
$$.method = method;
@@ -233,10 +237,49 @@ method_decl:
method->open_paren_token = $4.buffer;
method->args = $5.arg;
method->close_paren_token = $6.buffer;
+ method->hasId = false;
+ memset(&method->equals_token, 0, sizeof(buffer_type));
+ memset(&method->id, 0, sizeof(buffer_type));
method->semicolon_token = $7.buffer;
method->comments_token = &method->oneway_token;
$$.method = method;
}
+ | type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
+ method_type *method = (method_type*)malloc(sizeof(method_type));
+ method->interface_item.item_type = METHOD_TYPE;
+ method->interface_item.next = NULL;
+ method->oneway = false;
+ memset(&method->oneway_token, 0, sizeof(buffer_type));
+ method->type = $1.type;
+ method->name = $2.buffer;
+ method->open_paren_token = $3.buffer;
+ method->args = $4.arg;
+ method->close_paren_token = $5.buffer;
+ method->hasId = true;
+ method->equals_token = $6.buffer;
+ method->id = $7.buffer;
+ method->semicolon_token = $8.buffer;
+ method->comments_token = &method->type.type;
+ $$.method = method;
+ }
+ | ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
+ method_type *method = (method_type*)malloc(sizeof(method_type));
+ method->interface_item.item_type = METHOD_TYPE;
+ method->interface_item.next = NULL;
+ method->oneway = true;
+ method->oneway_token = $1.buffer;
+ method->type = $2.type;
+ method->name = $3.buffer;
+ method->open_paren_token = $4.buffer;
+ method->args = $5.arg;
+ method->close_paren_token = $6.buffer;
+ method->hasId = true;
+ method->equals_token = $7.buffer;
+ method->id = $8.buffer;
+ method->semicolon_token = $9.buffer;
+ method->comments_token = &method->oneway_token;
+ $$.method = method;
+ }
;
arg_list:
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
index f80a388eed55..f291ceb2b09f 100644
--- a/tools/aidl/generate_java_binder.cpp
+++ b/tools/aidl/generate_java_binder.cpp
@@ -260,7 +260,7 @@ generate_method(const method_type* method, Class* interface,
string transactCodeName = "TRANSACTION_";
transactCodeName += method->name.data;
- char transactCodeValue[50];
+ char transactCodeValue[60];
sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
Field* transactCode = new Field(STATIC | FINAL,
@@ -548,7 +548,8 @@ generate_binder_interface_class(const interface_type* iface)
interface_item_type* item = iface->interface_items;
while (item != NULL) {
if (item->item_type == METHOD_TYPE) {
- generate_method((method_type*)item, interface, stub, proxy, index);
+ method_type * method_item = (method_type*) item;
+ generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
}
item = item->next;
index++;
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 3c124d90aaae..2e4274da5afd 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -7,5 +7,6 @@
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 687a91feeb6f..e3d48fca5eb2 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -22,6 +22,7 @@ LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
+ icu4j \
layoutlib_api-prebuilt \
tools-common-prebuilt
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_charge_anim100.png b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_charge_anim100.png
new file mode 100644
index 000000000000..829378ea9f8f
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png
index bd44b529ee74..931daeddceb5 100644
--- a/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
new file mode 100644
index 000000000000..782ebfe3f2ba
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
new file mode 100644
index 000000000000..677b47137a3f
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
new file mode 100644
index 000000000000..a1b806266959
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
new file mode 100644
index 000000000000..fcdbefe9f506
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
new file mode 100644
index 000000000000..633d86482938
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
new file mode 100644
index 000000000000..4665e2a6fef9
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_charge_anim100.png b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_charge_anim100.png
new file mode 100644
index 000000000000..2773a70691a8
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
index c629387c20b8..6e1ac9189e8f 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/status_bar.xml b/tools/layoutlib/bridge/resources/bars/status_bar.xml
index d3c492eacf43..51b474dab97f 100644
--- a/tools/layoutlib/bridge/resources/bars/status_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/status_bar.xml
@@ -6,10 +6,12 @@
android:layout_weight="1"/>
<ImageView
android:layout_height="wrap_content"
- android:layout_width="wrap_content"/>
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"/>
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:layout_marginLeft="3dip"
- android:layout_marginRight="5dip"/>
+ android:layout_marginLeft="3dp"
+ android:layout_marginRight="5dp"
+ android:layout_marginTop="1dp"/>
</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_charge_anim100.png b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_charge_anim100.png
new file mode 100644
index 000000000000..c7fd7194fafa
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_battery_charge_anim100.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100644
index 000000000000..625c61dc4393
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index cbc199adece4..446d139b2161 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -218,7 +218,7 @@ public final class BridgeTypedArray extends TypedArray {
return defValue;
}
- if (s == null) {
+ if (s == null || s.length() == 0) {
return defValue;
}
@@ -894,7 +894,7 @@ public final class BridgeTypedArray extends TypedArray {
}
/**
- * Give back a previously retrieved StyledAttributes, for later re-use.
+ * Give back a previously retrieved TypedArray, for later re-use.
*/
@Override
public void recycle() {
diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
new file mode 100644
index 000000000000..62d0a0d6ae9d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2013 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.graphics;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.lang.UScriptRun;
+
+import android.graphics.Paint_Delegate.FontInfo;
+
+/**
+ * Render the text by breaking it into various scripts and using the right font for each script.
+ * Can be used to measure the text without actually drawing it.
+ */
+@SuppressWarnings("deprecation")
+public class BidiRenderer {
+
+ /* package */ static class ScriptRun {
+ int start;
+ int limit;
+ boolean isRtl;
+ int scriptCode;
+ FontInfo font;
+
+ public ScriptRun(int start, int limit, boolean isRtl) {
+ this.start = start;
+ this.limit = limit;
+ this.isRtl = isRtl;
+ this.scriptCode = UScript.INVALID_CODE;
+ }
+ }
+
+ /* package */ Graphics2D graphics;
+ /* package */ Paint_Delegate paint;
+ /* package */ char[] text;
+
+ /**
+ * @param graphics May be null.
+ * @param paint The Paint to use to get the fonts. Should not be null.
+ * @param text Unidirectional text. Should not be null.
+ */
+ /* package */ BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
+ assert (paint != null);
+ this.graphics = graphics;
+ this.paint = paint;
+ this.text = text;
+ }
+
+ /**
+ * Render unidirectional text.
+ *
+ * This method can also be used to measure the width of the text without actually drawing it.
+ *
+ * @param start index of the first character
+ * @param limit index of the first character that should not be rendered.
+ * @param isRtl is the text right-to-left
+ * @param advances If not null, then advances for each character to be rendered are returned
+ * here.
+ * @param advancesIndex index into advances from where the advances need to be filled.
+ * @param draw If true and {@link graphics} is not null, draw the rendered text on the graphics
+ * at the given co-ordinates
+ * @param x The x-coordinate of the left edge of where the text should be drawn on the given
+ * graphics.
+ * @param y The y-coordinate at which to draw the text on the given graphics.
+ * @return The x-coordinate of the right edge of the drawn text. In other words,
+ * x + the width of the text.
+ */
+ /* package */ float renderText(int start, int limit, boolean isRtl, float advances[],
+ int advancesIndex, boolean draw, float x, float y) {
+ // We break the text into scripts and then select font based on it and then render each of
+ // the script runs.
+ for (ScriptRun run : getScriptRuns(text, start, limit, isRtl, paint.getFonts())) {
+ int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
+ flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
+ x = renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw,
+ x, y);
+ advancesIndex += run.limit - run.start;
+ }
+ return x;
+ }
+
+ /**
+ * Render a script run. Use the preferred font to render as much as possible. This also
+ * implements a fallback mechanism to render characters that cannot be drawn using the
+ * preferred font.
+ *
+ * @return x + width of the text drawn.
+ */
+ private float renderScript(int start, int limit, FontInfo preferredFont, int flag,
+ float advances[], int advancesIndex, boolean draw, float x, float y) {
+ List<FontInfo> fonts = paint.getFonts();
+ if (fonts == null || preferredFont == null) {
+ return x;
+ }
+
+ while (start < limit) {
+ boolean foundFont = false;
+ int canDisplayUpTo = preferredFont.mFont.canDisplayUpTo(text, start, limit);
+ if (canDisplayUpTo == -1) {
+ return render(start, limit, preferredFont, flag, advances, advancesIndex, draw,
+ x, y);
+ } else if (canDisplayUpTo > start) { // can draw something
+ x = render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex,
+ draw, x, y);
+ advancesIndex += canDisplayUpTo - start;
+ start = canDisplayUpTo;
+ }
+
+ int charCount = Character.isHighSurrogate(text[start]) ? 2 : 1;
+ for (FontInfo font : fonts) {
+ canDisplayUpTo = font.mFont.canDisplayUpTo(text, start, start + charCount);
+ if (canDisplayUpTo == -1) {
+ x = render(start, start+charCount, font, flag, advances, advancesIndex, draw,
+ x, y);
+ start += charCount;
+ advancesIndex += charCount;
+ foundFont = true;
+ break;
+ }
+ }
+ if (!foundFont) {
+ // No font can display this char. Use the preferred font. The char will most
+ // probably appear as a box or a blank space. We could, probably, use some
+ // heuristics and break the character into the base character and diacritics and
+ // then draw it, but it's probably not worth the effort.
+ x = render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
+ draw, x, y);
+ start += charCount;
+ advancesIndex += charCount;
+ }
+ }
+ return x;
+ }
+
+ /**
+ * Render the text with the given font.
+ */
+ private float render(int start, int limit, FontInfo font, int flag, float advances[],
+ int advancesIndex, boolean draw, float x, float y) {
+
+ float totalAdvance = 0;
+ // Since the metrics don't have anti-aliasing set, we create a new FontRenderContext with
+ // the anti-aliasing set.
+ FontRenderContext f = font.mMetrics.getFontRenderContext();
+ FontRenderContext frc = new FontRenderContext(f.getTransform(), paint.isAntiAliased(),
+ f.usesFractionalMetrics());
+ GlyphVector gv = font.mFont.layoutGlyphVector(frc, text, start, limit, flag);
+ int ng = gv.getNumGlyphs();
+ int[] ci = gv.getGlyphCharIndices(0, ng, null);
+ for (int i = 0; i < ng; i++) {
+ float adv = gv.getGlyphMetrics(i).getAdvanceX();
+ if (advances != null) {
+ int adv_idx = advancesIndex + ci[i];
+ advances[adv_idx] += adv;
+ }
+ totalAdvance += adv;
+ }
+ if (draw && graphics != null) {
+ graphics.drawGlyphVector(gv, x, y);
+ }
+ return x + totalAdvance;
+ }
+
+ // --- Static helper methods ---
+
+ /* package */ static List<ScriptRun> getScriptRuns(char[] text, int start, int limit,
+ boolean isRtl, List<FontInfo> fonts) {
+ LinkedList<ScriptRun> scriptRuns = new LinkedList<ScriptRun>();
+
+ int count = limit - start;
+ UScriptRun uScriptRun = new UScriptRun(text, start, count);
+ while (uScriptRun.next()) {
+ int scriptStart = uScriptRun.getScriptStart();
+ int scriptLimit = uScriptRun.getScriptLimit();
+ ScriptRun run = new ScriptRun(scriptStart, scriptLimit, isRtl);
+ run.scriptCode = uScriptRun.getScriptCode();
+ setScriptFont(text, run, fonts);
+ scriptRuns.add(run);
+ }
+
+ return scriptRuns;
+ }
+
+ // TODO: Replace this method with one which returns the font based on the scriptCode.
+ private static void setScriptFont(char[] text, ScriptRun run,
+ List<FontInfo> fonts) {
+ for (FontInfo fontInfo : fonts) {
+ if (fontInfo.mFont.canDisplayUpTo(text, run.start, run.limit) == -1) {
+ run.font = fontInfo;
+ return;
+ }
+ }
+ run.font = fonts.get(0);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index b76b8cf7b47a..96616aaeca4f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -61,6 +61,7 @@ public final class Bitmap_Delegate {
private final Config mConfig;
private BufferedImage mImage;
private boolean mHasAlpha = true;
+ private boolean mHasMipMap = false; // TODO: check the default.
private int mGenerationId = 0;
@@ -185,6 +186,10 @@ public final class Bitmap_Delegate {
return mHasAlpha && mConfig != Config.RGB_565;
}
+ public boolean hasMipMap() {
+ // TODO: check if more checks are required as in hasAlpha.
+ return mHasMipMap;
+ }
/**
* Update the generationId.
*
@@ -336,6 +341,17 @@ public final class Bitmap_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static boolean nativeHasMipMap(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return true;
+ }
+
+ return delegate.mHasMipMap;
+ }
+
+ @LayoutlibDelegate
/*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -469,6 +485,17 @@ public final class Bitmap_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static void nativeSetHasMipMap(int nativeBitmap, boolean hasMipMap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mHasMipMap = hasMipMap;
+ }
+
+ @LayoutlibDelegate
/*package*/ static boolean nativeSameAs(int nb0, int nb1) {
Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
if (delegate1 == null) {
@@ -524,7 +551,7 @@ public final class Bitmap_Delegate {
int nativeInt = sManager.addNewDelegate(delegate);
// and create/return a new Bitmap with it
- return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/,
+ return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/,
density);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 9aed8c852118..da188644239d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -23,7 +23,6 @@ import com.android.layoutlib.bridge.impl.GcSnapshot;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Bitmap.Config;
-import android.graphics.Paint_Delegate.FontInfo;
import android.text.TextUtils;
import java.awt.Color;
@@ -35,7 +34,6 @@ import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.image.BufferedImage;
-import java.util.List;
/**
@@ -330,20 +328,19 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
+ /*package*/ static void copyNativeCanvasState(int srcCanvas, int dstCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
- if (canvasDelegate == null) {
+ Canvas_Delegate srcCanvasDelegate = sManager.getDelegate(srcCanvas);
+ if (srcCanvasDelegate == null) {
return;
}
// get the delegate from the native int.
- Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
- if (bitmapDelegate == null) {
+ Canvas_Delegate dstCanvasDelegate = sManager.getDelegate(dstCanvas);
+ if (dstCanvasDelegate == null) {
return;
}
-
- canvasDelegate.setBitmap(bitmapDelegate);
+ // TODO: actually copy the canvas state.
}
@LayoutlibDelegate
@@ -572,16 +569,14 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
- RectF rect,
- int native_edgeType) {
+ RectF rect) {
// FIXME properly implement quickReject
return false;
}
@LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
- int path,
- int native_edgeType) {
+ int path) {
// FIXME properly implement quickReject
return false;
}
@@ -589,8 +584,7 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
float left, float top,
- float right, float bottom,
- int native_edgeType) {
+ float right, float bottom) {
// FIXME properly implement quickReject
return false;
}
@@ -982,7 +976,8 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas,
final char[] text, final int index, final int count,
- final float startX, final float startY, int flags, int paint) {
+ final float startX, final float startY, final int flags, int paint) {
+
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
@Override
@@ -992,9 +987,10 @@ public final class Canvas_Delegate {
// Paint.TextAlign indicates how the text is positioned relative to X.
// LEFT is the default and there's nothing to do.
float x = startX;
- float y = startY;
+ int limit = index + count;
+ boolean isRtl = flags == Canvas.DIRECTION_RTL;
if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
- float m = paintDelegate.measureText(text, index, count);
+ float m = paintDelegate.measureText(text, index, count, isRtl);
if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
x -= m / 2;
} else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
@@ -1002,87 +998,15 @@ public final class Canvas_Delegate {
}
}
- List<FontInfo> fonts = paintDelegate.getFonts();
-
- if (fonts.size() > 0) {
- FontInfo mainFont = fonts.get(0);
- int i = index;
- int lastIndex = index + count;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // draw all the rest and exit.
- graphics.setFont(mainFont.mFont);
- graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
- return;
- } else if (upTo > 0) {
- // draw what's possible
- graphics.setFont(mainFont.mFont);
- graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
-
- // compute the width that was drawn to increase x
- x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
- // move index to the first non displayed char.
- i = upTo;
-
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < fonts.size() ; f++) {
- FontInfo fontInfo = fonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- // draw that char
- graphics.setFont(fontInfo.mFont);
- graphics.drawChars(text, i, charCount, (int)x, (int)y);
-
- // update x
- x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
- // update the index in the text, and move on
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, display it with the main font.
- // (it'll put a square probably)
- if (foundFont == false) {
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
- graphics.setFont(mainFont.mFont);
- graphics.drawChars(text, i, charCount, (int)x, (int)y);
-
- // measure it to advance x
- x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
- // and move to the next chars.
- i += charCount;
- }
- }
- }
+ new BidiRenderer(graphics, paintDelegate, text).renderText(
+ index, limit, isRtl, null, 0, true, x, startY);
}
});
}
@LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas, String text,
- int start, int end, float x, float y, int flags, int paint) {
+ int start, int end, float x, float y, final int flags, int paint) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 13826414cb27..41953ed28011 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -32,7 +32,6 @@ import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -569,29 +568,30 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
- int count) {
+ int count, int bidiFlags) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
return 0;
}
- return delegate.measureText(text, index, count);
+ return delegate.measureText(text, index, count, isRtl(bidiFlags));
}
@LayoutlibDelegate
- /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
- return native_measureText(thisPaint, text.toCharArray(), start, end - start);
+ /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end,
+ int bidiFlags) {
+ return native_measureText(thisPaint, text.toCharArray(), start, end - start, bidiFlags);
}
@LayoutlibDelegate
- /*package*/ static float native_measureText(Paint thisPaint, String text) {
- return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
+ /*package*/ static float native_measureText(Paint thisPaint, String text, int bidiFlags) {
+ return native_measureText(thisPaint, text.toCharArray(), 0, text.length(), bidiFlags);
}
@LayoutlibDelegate
/*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
- float maxWidth, float[] measuredWidth) {
+ float maxWidth, int bidiFlags, float[] measuredWidth) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -614,7 +614,7 @@ public class Paint_Delegate {
}
// measure from start to end
- float res = delegate.measureText(text, start, end - start + 1);
+ float res = delegate.measureText(text, start, end - start + 1, isRtl(bidiFlags));
if (measuredWidth != null) {
measuredWidth[measureIndex] = res;
@@ -634,9 +634,9 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
+ float maxWidth, int bidiFlags, float[] measuredWidth) {
return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
- measuredWidth);
+ bidiFlags, measuredWidth);
}
@LayoutlibDelegate
@@ -921,7 +921,7 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
- int count, float[] widths) {
+ int count, int bidiFlags, float[] widths) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -963,8 +963,9 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static int native_getTextWidths(int native_object, String text, int start,
- int end, float[] widths) {
- return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths);
+ int end, int bidiFlags, float[] widths) {
+ return native_getTextWidths(native_object, text.toCharArray(), start, end - start,
+ bidiFlags, widths);
}
@LayoutlibDelegate
@@ -977,58 +978,34 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex, int reserved) {
+ int flags, float[] advances, int advancesIndex) {
+
+ if (advances != null)
+ for (int i = advancesIndex; i< advancesIndex+count; i++)
+ advances[i]=0;
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
- if (delegate == null) {
+ if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
return 0.f;
}
+ boolean isRtl = isRtl(flags);
- if (delegate.mFonts.size() > 0) {
- // FIXME: handle multi-char characters (see measureText)
- float totalAdvance = 0;
- for (int i = 0; i < count; i++) {
- char c = text[i + index];
- boolean found = false;
- for (FontInfo info : delegate.mFonts) {
- if (info.mFont.canDisplay(c)) {
- float adv = info.mMetrics.charWidth(c);
- totalAdvance += adv;
- if (advances != null) {
- advances[i] = adv;
- }
-
- found = true;
- break;
- }
- }
-
- if (found == false) {
- // no advance for this char.
- if (advances != null) {
- advances[i] = 0.f;
- }
- }
- }
-
- return totalAdvance;
- }
-
- return 0;
-
+ int limit = index + count;
+ return new BidiRenderer(null, delegate, text).renderText(
+ index, limit, isRtl, advances, advancesIndex, false, 0, 0);
}
@LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, int reserved) {
- // FIXME: support contextStart, contextEnd and direction flag
+ int flags, float[] advances, int advancesIndex) {
+ // FIXME: support contextStart and contextEnd
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
- contextEnd - contextStart, flags, advances, advancesIndex, reserved);
+ contextEnd - contextStart, flags, advances, advancesIndex);
}
@LayoutlibDelegate
@@ -1067,29 +1044,23 @@ public class Paint_Delegate {
@LayoutlibDelegate
/*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
- int end, Rect bounds) {
- nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds);
+ int end, int bidiFlags, Rect bounds) {
+ nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bidiFlags,
+ bounds);
}
@LayoutlibDelegate
/*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
- int count, Rect bounds) {
+ int count, int bidiFlags, Rect bounds) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(nativePaint);
- if (delegate == null) {
+ if (delegate == null || delegate.mFonts == null || delegate.mFonts.size() == 0) {
return;
}
-
- // FIXME should test if the main font can display all those characters.
- // See MeasureText
- if (delegate.mFonts.size() > 0) {
- FontInfo mainInfo = delegate.mFonts.get(0);
-
- Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
- delegate.mFontContext);
- bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
- }
+ int w = (int) delegate.measureText(text, index, count, isRtl(bidiFlags));
+ int h= delegate.getFonts().get(0).mMetrics.getHeight();
+ bounds.set(0, 0, w, h);
}
@LayoutlibDelegate
@@ -1173,6 +1144,7 @@ public class Paint_Delegate {
info.mFont = info.mFont.deriveFont(new AffineTransform(
mTextScaleX, mTextSkewX, 0, 1, 0, 0));
}
+ // The metrics here don't have anti-aliasing set.
info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
infoList.add(info);
@@ -1182,63 +1154,9 @@ public class Paint_Delegate {
}
}
- /*package*/ float measureText(char[] text, int index, int count) {
-
- // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
- // Any change to this method should be reflected there as well
-
- if (mFonts.size() > 0) {
- FontInfo mainFont = mFonts.get(0);
- int i = index;
- int lastIndex = index + count;
- float total = 0f;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // shortcut to exit
- return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
- } else if (upTo > 0) {
- total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
- i = upTo;
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < mFonts.size() ; f++) {
- FontInfo fontInfo = mFonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- total += fontInfo.mMetrics.charsWidth(text, i, charCount);
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, measure it with the main font.
- if (foundFont == false) {
- int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
- total += mainFont.mMetrics.charsWidth(text, i, size);
- i += size;
- }
- }
-
- return total;
- }
-
- return 0;
+ /*package*/ float measureText(char[] text, int index, int count, boolean isRtl) {
+ return new BidiRenderer(null, this, text).renderText(
+ index, index + count, isRtl, null, 0, false, 0, 0);
}
private float getFontMetrics(FontMetrics metrics) {
@@ -1277,4 +1195,14 @@ public class Paint_Delegate {
}
}
+ private static boolean isRtl(int flag) {
+ switch(flag) {
+ case Paint.BIDI_RTL:
+ case Paint.BIDI_FORCE_RTL:
+ case Paint.BIDI_DEFAULT_RTL:
+ return true;
+ default:
+ return false;
+ }
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 2414d705be8a..8701cc8068a6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -188,11 +188,6 @@ public final class Typeface_Delegate {
return delegate.mStyle;
}
- @LayoutlibDelegate
- /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
- // This is for device testing only: pass
- }
-
// ---- Private delegate/helper methods ----
private Typeface_Delegate(String family, int style) {
diff --git a/tools/layoutlib/bridge/src/android/os/Looper_Accessor.java b/tools/layoutlib/bridge/src/android/os/Looper_Accessor.java
index 2961f9735890..09f3e47d7a14 100644
--- a/tools/layoutlib/bridge/src/android/os/Looper_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/os/Looper_Accessor.java
@@ -15,6 +15,8 @@
*/
package android.os;
+import java.lang.reflect.Field;
+
/**
* Class allowing access to package-protected methods/fields.
*/
@@ -23,5 +25,23 @@ public class Looper_Accessor {
public static void cleanupThread() {
// clean up the looper
Looper.sThreadLocal.remove();
+ try {
+ Field sMainLooper = Looper.class.getDeclaredField("sMainLooper");
+ sMainLooper.setAccessible(true);
+ sMainLooper.set(null, null);
+ } catch (SecurityException e) {
+ catchReflectionException();
+ } catch (IllegalArgumentException e) {
+ catchReflectionException();
+ } catch (NoSuchFieldException e) {
+ catchReflectionException();
+ } catch (IllegalAccessException e) {
+ catchReflectionException();
+ }
+
+ }
+
+ private static void catchReflectionException() {
+ assert(false);
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
index 52b8f348adf0..973fa0e9ef54 100644
--- a/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/AndroidBidi_Delegate.java
@@ -16,7 +16,10 @@
package android.text;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.ibm.icu.text.Bidi;
/**
@@ -29,9 +32,29 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
public class AndroidBidi_Delegate {
@LayoutlibDelegate
- /*package*/ static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) {
- // return the equivalent of Layout.DIR_LEFT_TO_RIGHT
- // TODO: actually figure the direction.
- return 0;
+ /*package*/ static int runBidi(int dir, char[] chars, byte[] charInfo, int count,
+ boolean haveInfo) {
+
+ switch (dir) {
+ case 0: // Layout.DIR_REQUEST_LTR
+ case 1: // Layout.DIR_REQUEST_RTL
+ break; // No change.
+ case -1:
+ dir = Bidi.LEVEL_DEFAULT_LTR;
+ break;
+ case -2:
+ dir = Bidi.LEVEL_DEFAULT_RTL;
+ break;
+ default:
+ // Invalid code. Log error, assume LEVEL_DEFAULT_LTR and continue.
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Invalid direction flag", null);
+ dir = Bidi.LEVEL_DEFAULT_LTR;
+ }
+ Bidi bidi = new Bidi(chars, 0, null, 0, count, dir);
+ if (charInfo != null) {
+ for (int i = 0; i < count; ++i)
+ charInfo[i] = bidi.getLevelAt(i);
+ }
+ return bidi.getParaLevel();
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
new file mode 100644
index 000000000000..15cd68789863
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/format/Time_Delegate.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 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.text.format;
+
+import java.util.Calendar;
+import java.util.UnknownFormatConversionException;
+import java.util.regex.Pattern;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation for native methods of {@link Time}
+ *
+ * Through the layoutlib_create tool, some native methods of Time have been replaced by calls to
+ * methods of the same name in this delegate class.
+ */
+public class Time_Delegate {
+
+ // Regex to match odd number of '%'.
+ private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)");
+
+ @LayoutlibDelegate
+ /*package*/ static String format1(Time thisTime, String format) {
+
+ try {
+ // Change the format by adding changing '%' to "%1$t". This is required to tell the
+ // formatter which argument to use from the argument list. '%%' is left as is. In the
+ // replacement string, $0 refers to matched pattern. \\1 means '1', written this way to
+ // separate it from 0. \\$ means '$', written this way to suppress the special meaning
+ // of $.
+ return String.format(
+ p.matcher(format).replaceAll("$0\\1\\$t"),
+ timeToCalendar(thisTime, Calendar.getInstance()));
+ } catch (UnknownFormatConversionException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format);
+ return format;
+ }
+ }
+
+ private static Calendar timeToCalendar(Time time, Calendar calendar) {
+ calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second);
+ return calendar;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 091c6e5e2a92..434b13132451 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -16,12 +16,14 @@
package android.view;
+import android.graphics.Point;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
@@ -30,13 +32,11 @@ import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Gravity;
import android.view.IApplicationToken;
-import android.view.IDisplayContentChangeListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowManager;
import android.view.IWindowSession;
-import android.view.WindowInfo;
import java.util.List;
@@ -87,7 +87,7 @@ public class IWindowManagerImpl implements IWindowManager {
// ---- unused implementation of IWindowManager ----
@Override
- public void addAppToken(int arg0, int arg1p5, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
boolean arg5)
throws RemoteException {
// TODO Auto-generated method stub
@@ -111,6 +111,12 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void setOverscan(int displayId, int left, int top, int right, int bottom)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void closeSystemDialogs(String arg0) throws RemoteException {
// TODO Auto-generated method stub
@@ -343,11 +349,31 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void getInitialDisplaySize(int displayId, Point size) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void getBaseDisplaySize(int displayId, Point size) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void setForcedDisplaySize(int displayId, int arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
@Override
+ public int getInitialDisplayDensity(int displayId) {
+ return -1;
+ }
+
+ @Override
+ public int getBaseDisplayDensity(int displayId) {
+ return -1;
+ }
+
+ @Override
public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
// TODO Auto-generated method stub
}
@@ -423,6 +449,10 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
+ public void removeRotationWatcher(IRotationWatcher arg0) throws RemoteException {
+ }
+
+ @Override
public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
return false;
}
@@ -446,7 +476,7 @@ public class IWindowManagerImpl implements IWindowManager {
public void lockNow(Bundle options) {
// TODO Auto-generated method stub
}
-
+
@Override
public boolean isSafeModeEnabled() {
return false;
@@ -464,43 +494,34 @@ public class IWindowManagerImpl implements IWindowManager {
}
@Override
- public float getWindowCompatibilityScale(IBinder windowToken) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
public void setInputFilter(IInputFilter filter) throws RemoteException {
// TODO Auto-generated method stub
}
@Override
- public void magnifyDisplay(int dipslayId, float scale, float offsetX, float offsetY)
- throws RemoteException {
+ public void getWindowFrame(IBinder token, Rect outFrame) {
// TODO Auto-generated method stub
}
@Override
- public void addDisplayContentChangeListener(int displayId,
- IDisplayContentChangeListener listener) throws RemoteException {
+ public void setMagnificationCallbacks(IMagnificationCallbacks callbacks) {
// TODO Auto-generated method stub
}
@Override
- public void removeDisplayContentChangeListener(int displayId,
- IDisplayContentChangeListener listener) throws RemoteException {
+ public void setMagnificationSpec(MagnificationSpec spec) {
// TODO Auto-generated method stub
}
@Override
- public WindowInfo getWindowInfo(IBinder token) throws RemoteException {
+ public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
// TODO Auto-generated method stub
return null;
}
@Override
- public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos)
- throws RemoteException {
+ public boolean isRotationFrozen() throws RemoteException {
// TODO Auto-generated method stub
+ return false;
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
index 7a6e52e4d65e..dc4f9c868185 100644
--- a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
@@ -22,6 +22,6 @@ package android.view.inputmethod;
public class InputMethodManager_Accessor {
public static void resetInstance() {
- InputMethodManager.mInstance = null;
+ InputMethodManager.sInstance = null;
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
index f0560401f219..7c98847a4cf3 100644
--- a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
@@ -35,28 +35,15 @@ public class InputMethodManager_Delegate {
// ---- Overridden methods ----
@LayoutlibDelegate
- /*package*/ static InputMethodManager getInstance(Looper mainLooper) {
- synchronized (InputMethodManager.mInstanceSync) {
- if (InputMethodManager.mInstance != null) {
- return InputMethodManager.mInstance;
+ /*package*/ static InputMethodManager getInstance() {
+ synchronized (InputMethodManager.class) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm == null) {
+ imm = new InputMethodManager(
+ new BridgeIInputMethodManager(), Looper.getMainLooper());
+ InputMethodManager.sInstance = imm;
}
-
- InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(),
- mainLooper);
- }
- return InputMethodManager.mInstance;
- }
-
- @LayoutlibDelegate
- /*package*/ static InputMethodManager getInstance(Context context) {
- synchronized (InputMethodManager.mInstanceSync) {
- if (InputMethodManager.mInstance != null) {
- return InputMethodManager.mInstance;
- }
-
- InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(),
- Looper.myLooper());
+ return imm;
}
- return InputMethodManager.mInstance;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index bf8658e402b0..ab4be7132967 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -35,6 +35,7 @@ import com.android.resources.ResourceType;
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
import com.android.util.Pair;
+import com.ibm.icu.util.ULocale;
import android.content.res.BridgeAssetManager;
import android.graphics.Bitmap;
@@ -64,6 +65,8 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
+ private static final String ICU_LOCALE_DIRECTION_RTL = "right-to-left";
+
public static class StaticMethodNotImplementedException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -211,7 +214,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
Capability.ANIMATED_VIEW_MANIPULATION,
Capability.ADAPTER_BINDING,
Capability.EXTENDED_VIEWINFO,
- Capability.FIXED_SCALABLE_NINE_PATCH);
+ Capability.FIXED_SCALABLE_NINE_PATCH,
+ Capability.RTL);
BridgeAssetManager.initSystem();
@@ -411,6 +415,20 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
throw new IllegalArgumentException("viewObject is not a View");
}
+ @Override
+ public boolean isRtl(String locale) {
+ return isLocaleRtl(locale);
+ }
+
+ public static boolean isLocaleRtl(String locale) {
+ if (locale == null) {
+ locale = "";
+ }
+ ULocale uLocale = new ULocale(locale);
+ return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL) ?
+ true : false;
+ }
+
/**
* Returns the lock for the bridge
*/
@@ -428,7 +446,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
// we need to make sure the Looper has been initialized for this thread.
// this is required for View that creates Handler objects.
if (Looper.myLooper() == null) {
- Looper.prepare();
+ Looper.prepareMainLooper();
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index f770cccf66e2..4aea38faacd4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -40,26 +40,30 @@ import java.util.ArrayList;
*/
public final class BridgeContentProvider implements IContentProvider {
@Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
+ public ContentProviderResult[] applyBatch(String callingPackage,
+ ArrayList<ContentProviderOperation> arg0)
throws RemoteException, OperationApplicationException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
+ public int bulkInsert(String callingPackage, Uri arg0, ContentValues[] arg1)
+ throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@Override
- public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
+ public Bundle call(String callingPackage, String arg0, String arg1, Bundle arg2)
+ throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
+ public int delete(String callingPackage, Uri arg0, String arg1, String[] arg2)
+ throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@@ -71,35 +75,35 @@ public final class BridgeContentProvider implements IContentProvider {
}
@Override
- public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
+ public Uri insert(String callingPackage, Uri arg0, ContentValues arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
+ public AssetFileDescriptor openAssetFile(String callingPackage, Uri arg0, String arg1)
+ throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
- public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
+ public ParcelFileDescriptor openFile(String callingPackage, Uri arg0, String arg1)
+ throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4,
- ICancellationSignal arg5) throws RemoteException {
+ public Cursor query(String callingPackage, Uri arg0, String[] arg1, String arg2, String[] arg3,
+ String arg4, ICancellationSignal arg5) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
- throws RemoteException {
+ public int update(String callingPackage, Uri arg0, ContentValues arg1, String arg2,
+ String[] arg3) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@@ -117,8 +121,8 @@ public final class BridgeContentProvider implements IContentProvider {
}
@Override
- public AssetFileDescriptor openTypedAssetFile(Uri arg0, String arg1, Bundle arg2)
- throws RemoteException, FileNotFoundException {
+ public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri arg0, String arg1,
+ Bundle arg2) throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index e2fced6af46b..99aa22811196 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -132,7 +132,8 @@ public final class BridgeContext extends Context {
RenderResources renderResources,
IProjectCallback projectCallback,
Configuration config,
- int targetSdkVersion) {
+ int targetSdkVersion,
+ boolean hasRtlSupport) {
mProjectKey = projectKey;
mMetrics = metrics;
mProjectCallback = projectCallback;
@@ -142,6 +143,9 @@ public final class BridgeContext extends Context {
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.targetSdkVersion = targetSdkVersion;
+ if (hasRtlSupport) {
+ mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
+ }
mWindowManager = new WindowManagerImpl(mMetrics);
}
@@ -1080,6 +1084,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public String getBasePackageName() {
+ // pass
+ return null;
+ }
+
+ @Override
public ApplicationInfo getApplicationInfo() {
return mApplicationInfo;
}
@@ -1200,6 +1210,11 @@ public final class BridgeContext extends Context {
}
@Override
+ public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+ // pass
+ }
+
+ @Override
public void sendOrderedBroadcast(Intent arg0, String arg1) {
// pass
@@ -1214,6 +1229,13 @@ public final class BridgeContext extends Context {
}
@Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
+ BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ // pass
+ }
+
+ @Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
// pass
}
@@ -1380,4 +1402,12 @@ public final class BridgeContext extends Context {
// pass
return null;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getUserId() {
+ return 0; // not used
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index fa660e675d03..df576d242291 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -47,7 +47,7 @@ public final class BridgeWindow implements IWindow {
}
@Override
- public void resized(Rect arg1, Rect arg2, Rect arg3,
+ public void resized(Rect arg1, Rect arg1p5, Rect arg2, Rect arg3,
boolean arg4, Configuration arg5) throws RemoteException {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 67b0a9cfa552..09e68785231d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -24,6 +24,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IWindow;
+import android.view.IWindowId;
import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.Surface;
@@ -86,7 +87,7 @@ public final class BridgeWindowSession implements IWindowSession {
}
@Override
public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
- int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b,
+ int arg4_5, Rect arg5Z, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b,
Surface arg8) throws RemoteException {
// pass for now.
return 0;
@@ -199,4 +200,10 @@ public final class BridgeWindowSession implements IWindowSession {
public void onRectangleOnScreenRequested(IBinder window, Rect rectangle, boolean immediate) {
// pass for now.
}
+
+ @Override
+ public IWindowId getWindowId(IBinder window) throws RemoteException {
+ // pass for now.
+ return null;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index ea9d8d929bc8..17b0eb641efa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -25,6 +25,7 @@ import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.Density;
+import com.android.resources.LayoutDirection;
import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
@@ -86,38 +87,53 @@ abstract class CustomBar extends LinearLayout {
}
}
- private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
- boolean tryOtherDensities) {
+ private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction,
+ String[] pathOut, boolean tryOtherDensities) {
// current density
Density density = densityInOut[0];
// bitmap url relative to this class
- pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
+ if (direction != null) {
+ pathOut[0] = "/bars/" + direction.getResourceValue() + "-" + density.getResourceValue()
+ + "/" + iconName;
+ } else {
+ pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
+ }
InputStream stream = getClass().getResourceAsStream(pathOut[0]);
if (stream == null && tryOtherDensities) {
for (Density d : Density.values()) {
if (d != density) {
densityInOut[0] = d;
- stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
+ stream = getIcon(iconName, densityInOut, direction, pathOut,
+ false /*tryOtherDensities*/);
if (stream != null) {
return stream;
}
}
}
+ // couldn't find resource with direction qualifier. try without.
+ if (direction != null) {
+ return getIcon(iconName, densityInOut, null, pathOut, true);
+ }
}
return stream;
}
protected void loadIcon(int index, String iconName, Density density) {
+ loadIcon(index, iconName, density, false);
+ }
+
+ protected void loadIcon(int index, String iconName, Density density, boolean isRtl) {
View child = getChildAt(index);
if (child instanceof ImageView) {
ImageView imageView = (ImageView) child;
String[] pathOut = new String[1];
Density[] densityInOut = new Density[] { density };
- InputStream stream = getIcon(iconName, densityInOut, pathOut,
+ LayoutDirection dir = isRtl ? LayoutDirection.RTL : LayoutDirection.LTR;
+ InputStream stream = getIcon(iconName, densityInOut, dir, pathOut,
true /*tryOtherDensities*/);
density = densityInOut[0];
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index cc90d6b33abe..84e676ed4bbd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge.bars;
import com.android.resources.Density;
+import com.android.layoutlib.bridge.Bridge;
import org.xmlpull.v1.XmlPullParserException;
@@ -26,7 +27,8 @@ import android.widget.TextView;
public class NavigationBar extends CustomBar {
- public NavigationBar(Context context, Density density, int orientation) throws XmlPullParserException {
+ public NavigationBar(Context context, Density density, int orientation, boolean isRtl,
+ boolean rtlEnabled) throws XmlPullParserException {
super(context, density, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml");
setBackgroundColor(0xFF000000);
@@ -37,14 +39,15 @@ public class NavigationBar extends CustomBar {
// 0 is a spacer.
int back = 1;
int recent = 3;
- if (orientation == LinearLayout.VERTICAL) {
+ if (orientation == LinearLayout.VERTICAL || (isRtl && !rtlEnabled)) {
+ // If RTL is enabled, then layoutlib mirrors the layout for us.
back = 3;
recent = 1;
}
- loadIcon(back, "ic_sysbar_back.png", density);
- loadIcon(2, "ic_sysbar_home.png", density);
- loadIcon(recent, "ic_sysbar_recent.png", density);
+ loadIcon(back, "ic_sysbar_back.png", density, isRtl);
+ loadIcon(2, "ic_sysbar_home.png", density, isRtl);
+ loadIcon(recent, "ic_sysbar_recent.png", density, isRtl);
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 5c084121d123..3692d967e9af 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -30,7 +30,10 @@ import android.widget.TextView;
public class StatusBar extends CustomBar {
- public StatusBar(Context context, Density density) throws XmlPullParserException {
+ public StatusBar(Context context, Density density, int direction, boolean RtlEnabled)
+ throws XmlPullParserException {
+ // FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
+
super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
// FIXME: use FILL_H?
@@ -42,10 +45,7 @@ public class StatusBar extends CustomBar {
// We do know the order though.
// 0 is the spacer
loadIcon(1, "stat_sys_wifi_signal_4_fully.png", density);
- Drawable drawable = loadIcon(2, ResourceType.DRAWABLE, "stat_sys_battery_charge");
- if (drawable instanceof LevelListDrawable) {
- ((LevelListDrawable) drawable).setLevel(100);
- }
+ loadIcon(2, "stat_sys_battery_charge_anim100.png", density);
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index 081ce67c7950..108b651e302c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -52,6 +52,8 @@ public final class FontLoader {
private static final String NODE_NAME = "name";
private static final String NODE_FILE = "file";
+ private static final String ATTRIBUTE_VARIANT = "variant";
+ private static final String ATTRIBUTE_VALUE_ELEGANT = "elegant";
private static final String FONT_SUFFIX_NONE = ".ttf";
private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
@@ -189,6 +191,7 @@ public final class FontLoader {
private FontInfo mFontInfo = null;
private final StringBuilder mBuilder = new StringBuilder();
private List<FontInfo> mFontList = new ArrayList<FontInfo>();
+ private boolean isCompactFont = true;
private FontHandler(String osFontsLocation) {
super();
@@ -209,8 +212,21 @@ public final class FontLoader {
mFontList = new ArrayList<FontInfo>();
} else if (NODE_FAMILY.equals(localName)) {
if (mFontList != null) {
+ mFontInfo = null;
+ }
+ } else if (NODE_NAME.equals(localName)) {
+ if (mFontList != null && mFontInfo == null) {
+ mFontInfo = new FontInfo();
+ }
+ } else if (NODE_FILE.equals(localName)) {
+ if (mFontList != null && mFontInfo == null) {
mFontInfo = new FontInfo();
}
+ if (ATTRIBUTE_VALUE_ELEGANT.equals(attributes.getValue(ATTRIBUTE_VARIANT))) {
+ isCompactFont = false;
+ } else {
+ isCompactFont = true;
+ }
}
mBuilder.setLength(0);
@@ -223,7 +239,9 @@ public final class FontLoader {
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
- mBuilder.append(ch, start, length);
+ if (isCompactFont) {
+ mBuilder.append(ch, start, length);
+ }
}
/* (non-Javadoc)
@@ -259,7 +277,7 @@ public final class FontLoader {
}
} else if (NODE_FILE.equals(localName)) {
// handle a new file for an existing Font Info
- if (mFontInfo != null) {
+ if (isCompactFont && mFontInfo != null) {
String fileName = trimXmlWhitespaces(mBuilder.toString());
Font font = getFont(fileName);
if (font != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index f109e3928b2b..87047b34371e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -30,6 +30,7 @@ import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.Density;
import com.android.resources.ResourceType;
+import com.android.resources.ScreenOrientation;
import com.android.resources.ScreenSize;
import android.content.res.Configuration;
@@ -120,7 +121,8 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
// build the context
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
- mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion());
+ mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
+ mParams.isRtlSupported());
setUp();
@@ -232,7 +234,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
sCurrentContext = mContext;
// create an InputMethodManager
- InputMethodManager.getInstance(Looper.myLooper());
+ InputMethodManager.getInstance();
LayoutLog currentLog = mParams.getLog();
Bridge.setLog(currentLog);
@@ -347,6 +349,23 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
config.compatScreenWidthDp = config.screenWidthDp;
config.compatScreenHeightDp = config.screenHeightDp;
+ ScreenOrientation orientation = hardwareConfig.getOrientation();
+ if (orientation != null) {
+ switch (orientation) {
+ case PORTRAIT:
+ config.orientation = Configuration.ORIENTATION_PORTRAIT;
+ break;
+ case LANDSCAPE:
+ config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ break;
+ case SQUARE:
+ config.orientation = Configuration.ORIENTATION_SQUARE;
+ break;
+ }
+ } else {
+ config.orientation = Configuration.ORIENTATION_UNDEFINED;
+ }
+
// TODO: fill in more config info.
return config;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c14af4add019..9ddbbf140df4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -225,13 +225,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
SessionParams params = getParams();
HardwareConfig hardwareConfig = params.getHardwareConfig();
BridgeContext context = getContext();
-
+ boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
+ int direction = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
// the view group that receives the window background.
ViewGroup backgroundView = null;
if (mWindowIsFloating || params.isForceNoDecor()) {
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
+ mViewRoot.setLayoutDirection(direction);
} else {
if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
/*
@@ -253,12 +255,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
the bottom
*/
LinearLayout topLayout = new LinearLayout(context);
+ topLayout.setLayoutDirection(direction);
mViewRoot = topLayout;
topLayout.setOrientation(LinearLayout.HORIZONTAL);
try {
NavigationBar navigationBar = new NavigationBar(context,
- hardwareConfig.getDensity(), LinearLayout.VERTICAL);
+ hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl,
+ params.isRtlSupported());
navigationBar.setLayoutParams(
new LinearLayout.LayoutParams(
mNavigationBarSize,
@@ -290,6 +294,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
LinearLayout topLayout = new LinearLayout(context);
topLayout.setOrientation(LinearLayout.VERTICAL);
+ topLayout.setLayoutDirection(direction);
// if we don't already have a view root this is it
if (mViewRoot == null) {
mViewRoot = topLayout;
@@ -301,13 +306,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// this is the case of soft buttons + vertical bar.
// this top layout is the first layout in the horizontal layout. see above)
- mViewRoot.addView(topLayout, 0);
+ if (isRtl && params.isRtlSupported()) {
+ // If RTL is enabled, layoutlib will mirror the layouts. So, add the
+ // topLayout to the right of Navigation Bar and layoutlib will draw it
+ // to the left.
+ mViewRoot.addView(topLayout);
+ } else {
+ // Add the top layout to the left of the Navigation Bar.
+ mViewRoot.addView(topLayout, 0);
+ }
}
if (mStatusBarSize > 0) {
// system bar
try {
- StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
+ StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(),
+ direction, params.isRtlSupported());
systemBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mStatusBarSize));
@@ -366,7 +380,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
// system bar
try {
NavigationBar navigationBar = new NavigationBar(context,
- hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
+ hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl,
+ params.isRtlSupported());
navigationBar.setLayoutParams(
new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, mNavigationBarSize));
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index e0414fe3ee4b..6c998afaa0ac 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -16,7 +16,6 @@
package com.android.layoutlib.bridge.impl.binding;
-import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
@@ -27,7 +26,6 @@ import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.util.Pair;
-import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -35,124 +33,27 @@ import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
- * Base adapter to do fake data binding in {@link AdapterView} objects.
+ * A Helper class to do fake data binding in {@link AdapterView} objects.
*/
-public class BaseAdapter {
-
- /**
- * This is the items provided by the adapter. They are dynamically generated.
- */
- protected final static class AdapterItem {
- private final DataBindingItem mItem;
- private final int mType;
- private final int mFullPosition;
- private final int mPositionPerType;
- private List<AdapterItem> mChildren;
-
- protected AdapterItem(DataBindingItem item, int type, int fullPosition,
- int positionPerType) {
- mItem = item;
- mType = type;
- mFullPosition = fullPosition;
- mPositionPerType = positionPerType;
- }
-
- void addChild(AdapterItem child) {
- if (mChildren == null) {
- mChildren = new ArrayList<AdapterItem>();
- }
-
- mChildren.add(child);
- }
-
- List<AdapterItem> getChildren() {
- if (mChildren != null) {
- return mChildren;
- }
-
- return Collections.emptyList();
- }
-
- int getType() {
- return mType;
- }
-
- int getFullPosition() {
- return mFullPosition;
- }
-
- int getPositionPerType() {
- return mPositionPerType;
- }
-
- DataBindingItem getDataBindingItem() {
- return mItem;
- }
- }
-
- private final AdapterBinding mBinding;
- private final IProjectCallback mCallback;
- private final ResourceReference mAdapterRef;
- private boolean mSkipCallbackParser = false;
-
- protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
-
- protected BaseAdapter(ResourceReference adapterRef, AdapterBinding binding,
- IProjectCallback callback) {
- mAdapterRef = adapterRef;
- mBinding = binding;
- mCallback = callback;
- }
-
- // ------- Some Adapter method used by all children classes.
-
- public boolean areAllItemsEnabled() {
- return true;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public boolean isEmpty() {
- return mItems.size() == 0;
- }
-
- public void registerDataSetObserver(DataSetObserver observer) {
- // pass
- }
-
- public void unregisterDataSetObserver(DataSetObserver observer) {
- // pass
- }
-
- // -------
-
-
- protected AdapterBinding getBinding() {
- return mBinding;
- }
+@SuppressWarnings("deprecation")
+public class AdapterHelper {
- protected View getView(AdapterItem item, AdapterItem parentItem, View convertView,
- ViewGroup parent) {
+ static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
+ IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
// we don't care about recycling here because we never scroll.
DataBindingItem dataBindingItem = item.getDataBindingItem();
BridgeContext context = RenderAction.getCurrentContext();
Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
- parent, false /*attachToRoot*/, mSkipCallbackParser);
+ parent, false /*attachToRoot*/, skipCallbackParser);
View view = pair.getFirst();
- mSkipCallbackParser |= pair.getSecond();
+ skipCallbackParser |= pair.getSecond();
if (view != null) {
- fillView(context, view, item, parentItem);
+ fillView(context, view, item, parentItem, callback, adapterRef);
} else {
// create a text view to display an error.
TextView tv = new TextView(context);
@@ -160,16 +61,16 @@ public class BaseAdapter {
view = tv;
}
- return view;
+ return Pair.of(view, skipCallbackParser);
}
- private void fillView(BridgeContext context, View view, AdapterItem item,
- AdapterItem parentItem) {
+ private static void fillView(BridgeContext context, View view, AdapterItem item,
+ AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
for (int i = 0 ; i < count ; i++) {
- fillView(context, group.getChildAt(i), item, parentItem);
+ fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
}
} else {
int id = view.getId();
@@ -184,8 +85,8 @@ public class BaseAdapter {
if (view instanceof TextView) {
TextView tv = (TextView) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
@@ -204,8 +105,8 @@ public class BaseAdapter {
if (view instanceof Checkable) {
Checkable cb = (Checkable) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
@@ -224,8 +125,8 @@ public class BaseAdapter {
if (view instanceof ImageView) {
ImageView iv = (ImageView) view;
- Object value = mCallback.getAdapterItemValue(
- mAdapterRef, context.getViewKey(view),
+ Object value = callback.getAdapterItemValue(
+ adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType,
fullParentPosition, parentPositionPerType,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
new file mode 100644
index 000000000000..8e28dbaf1a4d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.layoutlib.bridge.impl.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+
+/**
+ * This is the items provided by the adapter. They are dynamically generated.
+ */
+final class AdapterItem {
+ private final DataBindingItem mItem;
+ private final int mType;
+ private final int mFullPosition;
+ private final int mPositionPerType;
+ private List<AdapterItem> mChildren;
+
+ protected AdapterItem(DataBindingItem item, int type, int fullPosition,
+ int positionPerType) {
+ mItem = item;
+ mType = type;
+ mFullPosition = fullPosition;
+ mPositionPerType = positionPerType;
+ }
+
+ void addChild(AdapterItem child) {
+ if (mChildren == null) {
+ mChildren = new ArrayList<AdapterItem>();
+ }
+
+ mChildren.add(child);
+ }
+
+ List<AdapterItem> getChildren() {
+ if (mChildren != null) {
+ return mChildren;
+ }
+
+ return Collections.emptyList();
+ }
+
+ int getType() {
+ return mType;
+ }
+
+ int getFullPosition() {
+ return mFullPosition;
+ }
+
+ int getPositionPerType() {
+ return mPositionPerType;
+ }
+
+ DataBindingItem getDataBindingItem() {
+ return mItem;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index 22570b9cf865..9a13f5a36a89 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -20,10 +20,12 @@ import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
+import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;
@@ -35,17 +37,23 @@ import java.util.List;
* and {@link SpinnerAdapter}.
*
*/
-public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+@SuppressWarnings("deprecation")
+public class FakeAdapter extends BaseAdapter {
// don't use a set because the order is important.
private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
+ private final IProjectCallback mCallback;
+ private final ResourceReference mAdapterRef;
+ private final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
+ private boolean mSkipCallbackParser = false;
public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
- super(adapterRef, binding, callback);
+ mAdapterRef = adapterRef;
+ mCallback = callback;
- final int repeatCount = getBinding().getRepeatCount();
- final int itemCount = getBinding().getItemCount();
+ final int repeatCount = binding.getRepeatCount();
+ final int itemCount = binding.getItemCount();
// Need an array to count for each type.
// This is likely too big, but is the max it can be.
@@ -54,7 +62,7 @@ public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdap
// We put several repeating sets.
for (int r = 0 ; r < repeatCount ; r++) {
// loop on the type of list items, and add however many for each type.
- for (DataBindingItem dataBindingItem : getBinding()) {
+ for (DataBindingItem dataBindingItem : binding) {
ResourceReference viewRef = dataBindingItem.getViewReference();
int typeIndex = mTypes.indexOf(viewRef);
if (typeIndex == -1) {
@@ -103,7 +111,11 @@ public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdap
public View getView(int position, View convertView, ViewGroup parent) {
// we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(position);
- return getView(item, null /*parentGroup*/, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentGroup*/, parent,
+ mCallback, mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
+
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 199e0404a16b..e539579fb0ab 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -20,7 +20,9 @@ import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
+import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
@@ -29,8 +31,14 @@ import android.widget.HeterogeneousExpandableList;
import java.util.ArrayList;
import java.util.List;
-public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
- HeterogeneousExpandableList {
+@SuppressWarnings("deprecation")
+public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList {
+
+ private final IProjectCallback mCallback;
+ private final ResourceReference mAdapterRef;
+ private boolean mSkipCallbackParser = false;
+
+ protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
// don't use a set because the order is important.
private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
@@ -38,7 +46,8 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
- super(adapterRef, binding, callback);
+ mAdapterRef = adapterRef;
+ mCallback = callback;
createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
}
@@ -125,7 +134,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
ViewGroup parent) {
// we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(groupPosition);
- return getView(item, null /*parentItem*/, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentItem*/, parent,
+ mCallback, mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
}
@Override
@@ -134,7 +146,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
// we don't care about recycling here because we never scroll.
AdapterItem parentItem = mItems.get(groupPosition);
AdapterItem item = getChildItem(groupPosition, childPosition);
- return getView(item, parentItem, convertView, parent);
+ Pair<View, Boolean> pair = AdapterHelper.getView(item, parentItem, parent, mCallback,
+ mAdapterRef, mSkipCallbackParser);
+ mSkipCallbackParser = pair.getSecond();
+ return pair.getFirst();
}
@Override
@@ -172,6 +187,31 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
// pass
}
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ // pass
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ // pass
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mItems.isEmpty();
+ }
+
// ---- HeterogeneousExpandableList
@Override
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index fb2fc8545338..294d743e8cf9 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -44,6 +44,16 @@ public class ICU_Delegate {
// --- Native methods accessing ICU's database.
@LayoutlibDelegate
+ /*package*/ static String getBestDateTimePattern(String skeleton, String localeName) {
+ return ""; // TODO: check what the right value should be.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getCldrVersion() {
+ return "22.1.1"; // TODO: check what the right value should be.
+ }
+
+ @LayoutlibDelegate
/*package*/ static String getIcuVersion() {
return "unknown_layoutlib";
}
@@ -171,12 +181,18 @@ public class ICU_Delegate {
result.longStandAloneMonthNames = result.longMonthNames;
result.shortStandAloneMonthNames = result.shortMonthNames;
+ // The platform code expects this to begin at index 1, rather than 0. It maps it directly to
+ // the constants from java.util.Calendar.<weekday>
result.longWeekdayNames = new String[] {
- "Monday" ,"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
+ "", "Sunday", "Monday" ,"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
result.shortWeekdayNames = new String[] {
- "Mon" ,"Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ "", "Sun", "Mon" ,"Tue", "Wed", "Thu", "Fri", "Sat" };
+ result.tinyWeekdayNames = new String[] {
+ "", "S", "M", "T", "W", "T", "F", "S" };
+
result.longStandAloneWeekdayNames = result.longWeekdayNames;
result.shortStandAloneWeekdayNames = result.shortWeekdayNames;
+ result.tinyStandAloneWeekdayNames = result.tinyWeekdayNames;
result.fullTimeFormat = "";
result.longTimeFormat = "";
diff --git a/tools/layoutlib/create/.classpath b/tools/layoutlib/create/.classpath
index dbc4cfd392a7..cd8bb0d7d3fb 100644
--- a/tools/layoutlib/create/.classpath
+++ b/tools/layoutlib/create/.classpath
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
- <classpathentry excluding="mock_android/" kind="src" path="tests"/>
+ <classpathentry excluding="mock_data/" kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-4.0.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-4.0.jar" sourcepath="/ANDROID_PLAT/prebuilts/tools/common/asm-tools/src-4.0.zip"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index 894611b3e728..72fc9329669b 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -71,6 +71,9 @@ class names, for example "android.*.R**" ("*" does not matches dots whilst "**"
and "." and "$" are interpreted as-is).
In practice we almost but not quite request the inclusion of full packages.
+The analyzer is also given a list of classes to exclude. A fake implementation of these
+classes is injected by the Generator.
+
With this information, the analyzer parses the input zip to find all the classes.
All classes deriving from the requested bases classes are kept.
All classes which name matched the glob pattern are kept.
@@ -93,6 +96,7 @@ and lists:
- specific methods for which to delegate calls.
- specific methods to remove based on their return type.
- specific classes to rename.
+- specific classes to refactor.
Each of these are specific strategies we use to be able to modify the Android code
to fit within the Eclipse renderer. These strategies are explained beow.
@@ -100,10 +104,7 @@ to fit within the Eclipse renderer. These strategies are explained beow.
The core method of the generator is transform(): it takes an input ASM ClassReader
and modifies it to produce a byte array suitable for the final JAR file.
-The first step of the transformation is changing the name of the class in case
-we requested the class to be renamed. This uses the RenameClassAdapter to also rename
-all inner classes and references in methods and types. Note that other classes are
-not transformed and keep referencing the original name.
+The first step of the transformation is to implement the method delegates.
The TransformClassAdapter is then used to process the potentially renamed class.
All protected or private classes are market as public.
@@ -115,11 +116,25 @@ Methods are also changed from protected/private to public.
The code of the methods is then kept as-is, except for native methods which are
replaced by a stub. Methods that are to be overridden are also replaced by a stub.
-The transformed class is then fed through the DelegateClassAdapter to implement
-method delegates.
-
Finally fields are also visited and changed from protected/private to public.
+The next step of the transformation is changing the name of the class in case
+we requested the class to be renamed. This uses the RenameClassAdapter to also rename
+all inner classes and references in methods and types. Note that other classes are
+not transformed and keep referencing the original name.
+
+The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but
+updates the references in all classes. This is used to update the references of classes
+in the java package that were added in the Dalvik VM but are not a part of the standard
+JVM. The existing classes are modified to update all references to these non-standard
+classes. An alternate implementation of these (com.android.tools.layoutlib.java.*) is
+injected.
+
+The ClassAdapters are chained together to achieve the desired output. (Look at section
+2.2.7 Transformation chains in the asm user guide, link in the References.) The order of
+execution of these is:
+ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
+RefactorClassAdapter -> ClassWriter
- Method stubs
--------------
@@ -141,19 +156,27 @@ This strategy is now obsolete and replaced by the method delegates.
- Strategies
------------
-We currently have 4 strategies to deal with overriding the rendering code
+We currently have 6 strategies to deal with overriding the rendering code
and make it run in Eclipse. Most of these strategies are implemented hand-in-hand
by the bridge (which runs in Eclipse) and the generator.
1- Class Injection
-This is the easiest: we currently inject 4 classes, namely:
+This is the easiest: we currently inject the following classes:
- OverrideMethod and its associated MethodListener and MethodAdapter are used
to intercept calls to some specific methods that are stubbed out and change
their return value.
- CreateInfo class, which configured the generator. Not used yet, but could
in theory help us track what the generator changed.
+- AutoCloseable is part of Java 7. To enable us to still run on Java 6, a new class is
+ injected. The implementation for the class has been taken from Android's libcore
+ (platform/libcore/luni/src/main/java/java/lang/AutoCloseable.java).
+- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM.
+ They are added to the Dalvik VM for performance reasons. An implementation that is very
+ close to the original (which is at platform/libcore/luni/src/main/java/...) is injected.
+ Since these classees were in part of the java package, where we can't inject classes,
+ all references to these have been updated (See strategy 4- Refactoring Classes).
2- Overriding methods
@@ -189,7 +212,15 @@ we don't control object creation.
This won't rename/replace the inner static methods of a given class.
-4- Method erasure based on return type
+4- Refactoring classes
+
+This is very similar to the Renaming classes except that it also updates the reference in
+all classes. This is done for classes which are added to the Dalvik VM for performance
+reasons but are not present in the Standard Java VM. An implementation for these classes
+is also injected.
+
+
+5- Method erasure based on return type
This is mostly an implementation detail of the bridge: in the Paint class
mentioned above, some inner static classes are used to pass around
@@ -201,7 +232,7 @@ example, the inner class Paint$Style in the Paint class should be discarded and
bridge will provide its own implementation.
-5- Method Delegates
+6- Method Delegates
This strategy is used to override method implementations.
Given a method SomeClass.MethodName(), 1 or 2 methods are generated:
@@ -233,7 +264,7 @@ Bytecode opcode list:
http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
ASM user guide:
- http://download.forge.objectweb.org/asm/asm-guide.pdf
+ http://download.forge.objectweb.org/asm/asm4-guide.pdf
--
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
new file mode 100644
index 000000000000..b2caa25b9c29
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.signature.SignatureWriter;
+
+/**
+ * Provides the common code for RenameClassAdapter and RefactorClassAdapter. It
+ * goes through the complete class and finds references to other classes. It
+ * then calls {@link #renameInternalType(String)} to convert the className to
+ * the new value, if need be.
+ */
+public abstract class AbstractClassAdapter extends ClassVisitor {
+
+ /**
+ * Returns the new FQCN for the class, if the reference to this class needs
+ * to be updated. Else, it returns the same string.
+ * @param name Old FQCN
+ * @return New FQCN if it needs to be renamed, else the old FQCN
+ */
+ abstract String renameInternalType(String name);
+
+ public AbstractClassAdapter(ClassVisitor cv) {
+ super(Opcodes.ASM4, cv);
+ }
+
+ /**
+ * Renames a type descriptor, e.g. "Lcom.package.MyClass;"
+ * If the type doesn't need to be renamed, returns the input string as-is.
+ */
+ String renameTypeDesc(String desc) {
+ if (desc == null) {
+ return null;
+ }
+
+ return renameType(Type.getType(desc));
+ }
+
+ /**
+ * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
+ * object element, e.g. "[Lcom.package.MyClass;"
+ * If the type doesn't need to be renamed, returns the internal name of the input type.
+ */
+ String renameType(Type type) {
+ if (type == null) {
+ return null;
+ }
+
+ if (type.getSort() == Type.OBJECT) {
+ String in = type.getInternalName();
+ return "L" + renameInternalType(in) + ";";
+ } else if (type.getSort() == Type.ARRAY) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = type.getDimensions(); n > 0; n--) {
+ sb.append('[');
+ }
+ sb.append(renameType(type.getElementType()));
+ return sb.toString();
+ }
+ return type.getDescriptor();
+ }
+
+ /**
+ * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
+ * object element, e.g. "[Lcom.package.MyClass;".
+ * This is like renameType() except that it returns a Type object.
+ * If the type doesn't need to be renamed, returns the input type object.
+ */
+ Type renameTypeAsType(Type type) {
+ if (type == null) {
+ return null;
+ }
+
+ if (type.getSort() == Type.OBJECT) {
+ String in = type.getInternalName();
+ String newIn = renameInternalType(in);
+ if (newIn != in) {
+ return Type.getType("L" + newIn + ";");
+ }
+ } else if (type.getSort() == Type.ARRAY) {
+ StringBuilder sb = new StringBuilder();
+ for (int n = type.getDimensions(); n > 0; n--) {
+ sb.append('[');
+ }
+ sb.append(renameType(type.getElementType()));
+ return Type.getType(sb.toString());
+ }
+ return type;
+ }
+
+ /**
+ * Renames a method descriptor, i.e. applies renameType to all arguments and to the
+ * return value.
+ */
+ String renameMethodDesc(String desc) {
+ if (desc == null) {
+ return null;
+ }
+
+ Type[] args = Type.getArgumentTypes(desc);
+
+ StringBuilder sb = new StringBuilder("(");
+ for (Type arg : args) {
+ String name = renameType(arg);
+ sb.append(name);
+ }
+ sb.append(')');
+
+ Type ret = Type.getReturnType(desc);
+ String name = renameType(ret);
+ sb.append(name);
+
+ return sb.toString();
+ }
+
+
+ /**
+ * Renames the ClassSignature handled by ClassVisitor.visit
+ * or the MethodTypeSignature handled by ClassVisitor.visitMethod.
+ */
+ String renameTypeSignature(String sig) {
+ if (sig == null) {
+ return null;
+ }
+ SignatureReader reader = new SignatureReader(sig);
+ SignatureWriter writer = new SignatureWriter();
+ reader.accept(new RenameSignatureAdapter(writer));
+ sig = writer.toString();
+ return sig;
+ }
+
+
+ /**
+ * Renames the FieldTypeSignature handled by ClassVisitor.visitField
+ * or MethodVisitor.visitLocalVariable.
+ */
+ String renameFieldSignature(String sig) {
+ return renameTypeSignature(sig);
+ }
+
+
+ //----------------------------------
+ // Methods from the ClassAdapter
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ name = renameInternalType(name);
+ superName = renameInternalType(superName);
+ signature = renameTypeSignature(signature);
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; ++i) {
+ interfaces[i] = renameInternalType(interfaces[i]);
+ }
+ }
+
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ name = renameInternalType(name);
+ outerName = renameInternalType(outerName);
+ super.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ @Override
+ public void visitOuterClass(String owner, String name, String desc) {
+ super.visitOuterClass(renameInternalType(owner), name, renameTypeDesc(desc));
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ desc = renameMethodDesc(desc);
+ signature = renameTypeSignature(signature);
+ MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
+ return new RenameMethodAdapter(mw);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ desc = renameTypeDesc(desc);
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc,
+ String signature, Object value) {
+ desc = renameTypeDesc(desc);
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+
+ //----------------------------------
+
+ /**
+ * A method visitor that renames all references from an old class name to a new class name.
+ */
+ public class RenameMethodAdapter extends MethodVisitor {
+
+ /**
+ * Creates a method visitor that renames all references from a given old name to a given new
+ * name. The method visitor will also rename all inner classes.
+ * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
+ */
+ public RenameMethodAdapter(MethodVisitor mv) {
+ super(Opcodes.ASM4, mv);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ desc = renameTypeDesc(desc);
+
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
+ desc = renameTypeDesc(desc);
+
+ return super.visitParameterAnnotation(parameter, desc, visible);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ // The type sometimes turns out to be a type descriptor. We try to detect it and fix.
+ if (type.indexOf(';') > 0) {
+ type = renameTypeDesc(type);
+ } else {
+ type = renameInternalType(type);
+ }
+ super.visitTypeInsn(opcode, type);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ owner = renameInternalType(owner);
+ desc = renameTypeDesc(desc);
+
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ // The owner sometimes turns out to be a type descriptor. We try to detect it and fix.
+ if (owner.indexOf(';') > 0) {
+ owner = renameTypeDesc(owner);
+ } else {
+ owner = renameInternalType(owner);
+ }
+ desc = renameMethodDesc(desc);
+
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst) {
+ // If cst is a Type, this means the code is trying to pull the .class constant
+ // for this class, so it needs to be renamed too.
+ if (cst instanceof Type) {
+ cst = renameTypeAsType((Type) cst);
+ }
+ super.visitLdcInsn(cst);
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ desc = renameTypeDesc(desc);
+
+ super.visitMultiANewArrayInsn(desc, dims);
+ }
+
+ @Override
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ type = renameInternalType(type);
+
+ super.visitTryCatchBlock(start, end, handler, type);
+ }
+
+ @Override
+ public void visitLocalVariable(String name, String desc, String signature,
+ Label start, Label end, int index) {
+ desc = renameTypeDesc(desc);
+ signature = renameFieldSignature(signature);
+
+ super.visitLocalVariable(name, desc, signature, start, end, index);
+ }
+
+ }
+
+ //----------------------------------
+
+ public class RenameSignatureAdapter extends SignatureVisitor {
+
+ private final SignatureVisitor mSv;
+
+ public RenameSignatureAdapter(SignatureVisitor sv) {
+ super(Opcodes.ASM4);
+ mSv = sv;
+ }
+
+ @Override
+ public void visitClassType(String name) {
+ name = renameInternalType(name);
+ mSv.visitClassType(name);
+ }
+
+ @Override
+ public void visitInnerClassType(String name) {
+ name = renameInternalType(name);
+ mSv.visitInnerClassType(name);
+ }
+
+ @Override
+ public SignatureVisitor visitArrayType() {
+ SignatureVisitor sv = mSv.visitArrayType();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public void visitBaseType(char descriptor) {
+ mSv.visitBaseType(descriptor);
+ }
+
+ @Override
+ public SignatureVisitor visitClassBound() {
+ SignatureVisitor sv = mSv.visitClassBound();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public void visitEnd() {
+ mSv.visitEnd();
+ }
+
+ @Override
+ public SignatureVisitor visitExceptionType() {
+ SignatureVisitor sv = mSv.visitExceptionType();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public void visitFormalTypeParameter(String name) {
+ mSv.visitFormalTypeParameter(name);
+ }
+
+ @Override
+ public SignatureVisitor visitInterface() {
+ SignatureVisitor sv = mSv.visitInterface();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public SignatureVisitor visitInterfaceBound() {
+ SignatureVisitor sv = mSv.visitInterfaceBound();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public SignatureVisitor visitParameterType() {
+ SignatureVisitor sv = mSv.visitParameterType();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public SignatureVisitor visitReturnType() {
+ SignatureVisitor sv = mSv.visitReturnType();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public SignatureVisitor visitSuperclass() {
+ SignatureVisitor sv = mSv.visitSuperclass();
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public void visitTypeArgument() {
+ mSv.visitTypeArgument();
+ }
+
+ @Override
+ public SignatureVisitor visitTypeArgument(char wildcard) {
+ SignatureVisitor sv = mSv.visitTypeArgument(wildcard);
+ return new RenameSignatureAdapter(sv);
+ }
+
+ @Override
+ public void visitTypeVariable(String name) {
+ mSv.visitTypeVariable(name);
+ }
+
+ }
+}
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 412695f2661a..1572a4034432 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
@@ -34,6 +34,7 @@ import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -57,6 +58,8 @@ public class AsmAnalyzer {
private final String[] mDeriveFrom;
/** Glob patterns of classes to keep, e.g. "com.foo.*" */
private final String[] mIncludeGlobs;
+ /** The set of classes to exclude.*/
+ private final Set<String> mExcludedClasses;
/**
* Creates a new analyzer.
@@ -69,12 +72,13 @@ public class AsmAnalyzer {
* ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
*/
public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen,
- String[] deriveFrom, String[] includeGlobs) {
+ String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) {
mLog = log;
mGen = gen;
mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>();
mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
+ mExcludedClasses = excludeClasses;
}
/**
@@ -82,9 +86,6 @@ public class AsmAnalyzer {
* Fills the generator with classes & dependencies found.
*/
public void analyze() throws IOException, LogAbortException {
-
- AsmAnalyzer visitor = this;
-
Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
mOsSourceJar.size() > 1 ? "s" : "");
@@ -232,7 +233,7 @@ public class AsmAnalyzer {
*/
void findClassesDerivingFrom(String super_name, Map<String, ClassReader> zipClasses,
Map<String, ClassReader> inOutFound) throws LogAbortException {
- ClassReader super_clazz = findClass(super_name, zipClasses, inOutFound);
+ findClass(super_name, zipClasses, inOutFound);
for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
String className = entry.getKey();
@@ -363,11 +364,12 @@ public class AsmAnalyzer {
className = internalToBinaryClassName(className);
- // exclude classes that have already been found
+ // exclude classes that have already been found or are marked to be excluded
if (mInKeep.containsKey(className) ||
mOutKeep.containsKey(className) ||
mInDeps.containsKey(className) ||
- mOutDeps.containsKey(className)) {
+ mOutDeps.containsKey(className) ||
+ mExcludedClasses.contains(getBaseName(className))) {
return;
}
@@ -451,6 +453,13 @@ public class AsmAnalyzer {
}
}
+ private String getBaseName(String className) {
+ int pos = className.indexOf('$');
+ if (pos > 0) {
+ return className.substring(0, pos);
+ }
+ return className;
+ }
// ---------------------------------------------------
// --- ClassVisitor, FieldVisitor
@@ -682,7 +691,7 @@ public class AsmAnalyzer {
}
@Override
- public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
// pass -- table switch instruction
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index a9ede265b5d8..b10256127ae8 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -65,6 +65,9 @@ public class AsmGenerator {
/** A map { FQCN => set { method names } } of methods to rewrite as delegates.
* The special name {@link DelegateClassAdapter#ALL_NATIVES} can be used as in internal set. */
private final HashMap<String, Set<String>> mDelegateMethods;
+ /** FQCN Names of classes to refactor. All reference to old-FQCN will be updated to new-FQCN.
+ * map old-FQCN => new-FQCN */
+ private final HashMap<String, String> mRefactorClasses;
/**
* Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -119,6 +122,17 @@ public class AsmGenerator {
mClassesNotRenamed.add(oldFqcn);
}
+ // Create a map of classes to be refactored.
+ mRefactorClasses = new HashMap<String, String>();
+ String[] refactorClasses = createInfo.getJavaPkgClasses();
+ n = refactorClasses.length;
+ for (int i = 0; i < n; i += 2) {
+ assert i + 1 < n;
+ String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
+ String newFqcn = binaryToInternalClassName(refactorClasses[i + 1]);
+ mRefactorClasses.put(oldFqcn, newFqcn);;
+ }
+
// create the map of renamed class -> return type of method to delete.
mDeleteReturns = new HashMap<String, Set<String>>();
String[] deleteReturns = createInfo.getDeleteReturns();
@@ -308,14 +322,14 @@ public class AsmGenerator {
// original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- ClassVisitor rv = cw;
+ ClassVisitor cv = new RefactorClassAdapter(cw, mRefactorClasses);
if (newName != className) {
- rv = new RenameClassAdapter(cw, className, newName);
+ cv = new RenameClassAdapter(cv, className, newName);
}
- ClassVisitor cv = new TransformClassAdapter(mLog, mStubMethods,
+ cv = new TransformClassAdapter(mLog, mStubMethods,
mDeleteReturns.get(className),
- newName, rv,
+ newName, cv,
stubNativesOnly, stubNativesOnly || hasNativeMethods);
Set<String> delegateMethods = mDelegateMethods.get(className);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index d9550404d48a..7099a4bafab7 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -17,6 +17,10 @@
package com.android.tools.layoutlib.create;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.java.AutoCloseable;
+import com.android.tools.layoutlib.java.Charsets;
+import com.android.tools.layoutlib.java.IntegralToString;
+import com.android.tools.layoutlib.java.UnsafeByteSequence;
/**
* Describes the work to be done by {@link AsmGenerator}.
@@ -84,6 +88,15 @@ public final class CreateInfo implements ICreateInfo {
return DELETE_RETURNS;
}
+ /**
+ * Returns the list of classes to refactor, must be an even list: the binary FQCN of class to
+ * replace followed by the new FQCN. All references to the old class should be updated to the
+ * new class. The list can be empty but must not be null.
+ */
+ @Override
+ public String[] getJavaPkgClasses() {
+ return JAVA_PKG_CLASSES;
+ }
//-----
/**
@@ -95,7 +108,12 @@ public final class CreateInfo implements ICreateInfo {
MethodAdapter.class,
ICreateInfo.class,
CreateInfo.class,
- LayoutlibDelegate.class
+ LayoutlibDelegate.class,
+ /* Java package classes */
+ AutoCloseable.class,
+ IntegralToString.class,
+ UnsafeByteSequence.class,
+ Charsets.class,
};
/**
@@ -111,6 +129,7 @@ public final class CreateInfo implements ICreateInfo {
"android.os.HandlerThread#run",
"android.os.Build#getString",
"android.text.format.DateFormat#is24HourFormat",
+ "android.text.format.Time#format1",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
"android.view.LayoutInflater#rInflate",
@@ -195,6 +214,19 @@ public final class CreateInfo implements ICreateInfo {
};
/**
+ * The list of class references to update, must be an even list: the binary
+ * FQCN of class to replace followed by the new FQCN. The classes to
+ * replace are to be excluded from the output.
+ */
+ private final static String[] JAVA_PKG_CLASSES =
+ new String[] {
+ "java.lang.AutoCloseable", "com.android.tools.layoutlib.java.AutoCloseable",
+ "java.nio.charset.Charsets", "com.android.tools.layoutlib.java.Charsets",
+ "java.lang.IntegralToString", "com.android.tools.layoutlib.java.IntegralToString",
+ "java.lang.UnsafeByteSequence", "com.android.tools.layoutlib.java.UnsafeByteSequence",
+ };
+
+ /**
* List of classes for which the methods returning them should be deleted.
* The array contains a list of null terminated section starting with the name of the class
* to rename in which the methods are deleted, followed by a list of return types identifying
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 40c1706d9ed0..9387814ec204 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -62,4 +62,11 @@ public interface ICreateInfo {
*/
public abstract String[] getDeleteReturns();
+ /**
+ * Returns the list of classes to refactor, must be an even list: the
+ * binary FQCN of class to replace followed by the new FQCN. All references
+ * to the old class should be updated to the new class.
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getJavaPkgClasses();
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 9cd74db3445b..ba23048aee7b 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -18,6 +18,7 @@ package com.android.tools.layoutlib.create;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -86,7 +87,9 @@ public class Main {
}
try {
- AsmGenerator agen = new AsmGenerator(log, osDestJar, new CreateInfo());
+ CreateInfo info = new CreateInfo();
+ Set<String> excludeClasses = getExcludedClasses(info);
+ AsmGenerator agen = new AsmGenerator(log, osDestJar, info);
AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,
new String[] { // derived from
@@ -110,7 +113,8 @@ public class Main {
"android.pim.*", // for datepicker
"android.os.*", // for android.os.Handler
"android.database.ContentObserver", // for Digital clock
- });
+ },
+ excludeClasses);
aa.analyze();
agen.generate();
@@ -146,6 +150,16 @@ public class Main {
return 1;
}
+ private static Set<String> getExcludedClasses(CreateInfo info) {
+ String[] refactoredClasses = info.getJavaPkgClasses();
+ Set<String> excludedClasses = new HashSet<String>(refactoredClasses.length);
+ for (int i = 0; i < refactoredClasses.length; i+=2) {
+ excludedClasses.add(refactoredClasses[i]);
+ }
+ return excludedClasses;
+
+ }
+
private static int listDeps(ArrayList<String> osJarPath, Log log) {
DependencyFinder df = new DependencyFinder(log);
try {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
new file mode 100644
index 000000000000..91161f573b33
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RefactorClassAdapter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.create;
+
+import java.util.HashMap;
+
+import org.objectweb.asm.ClassVisitor;
+
+public class RefactorClassAdapter extends AbstractClassAdapter {
+
+ private final HashMap<String, String> mRefactorClasses;
+
+ RefactorClassAdapter(ClassVisitor cv, HashMap<String, String> refactorClasses) {
+ super(cv);
+ mRefactorClasses = refactorClasses;
+ }
+
+ @Override
+ protected String renameInternalType(String oldClassName) {
+ if (oldClassName != null) {
+ String newName = mRefactorClasses.get(oldClassName);
+ if (newName != null) {
+ return newName;
+ }
+ int pos = oldClassName.indexOf('$');
+ if (pos > 0) {
+ newName = mRefactorClasses.get(oldClassName.substring(0, pos));
+ if (newName != null) {
+ return newName + oldClassName.substring(pos);
+ }
+ }
+ }
+ return oldClassName;
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
index 383cbb8e3373..661074c7327a 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java
@@ -16,17 +16,7 @@
package com.android.tools.layoutlib.create;
-import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.signature.SignatureReader;
-import org.objectweb.asm.signature.SignatureVisitor;
-import org.objectweb.asm.signature.SignatureWriter;
/**
* This class visitor renames a class from a given old name to a given new name.
@@ -36,7 +26,7 @@ import org.objectweb.asm.signature.SignatureWriter;
* For inner classes, this handles only the case where the outer class name changes.
* The inner class name should remain the same.
*/
-public class RenameClassAdapter extends ClassVisitor {
+public class RenameClassAdapter extends AbstractClassAdapter {
private final String mOldName;
@@ -49,8 +39,8 @@ public class RenameClassAdapter extends ClassVisitor {
* The class visitor will also rename all inner classes and references in the methods.
* The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
*/
- public RenameClassAdapter(ClassWriter cv, String oldName, String newName) {
- super(Opcodes.ASM4, cv);
+ public RenameClassAdapter(ClassVisitor cv, String oldName, String newName) {
+ super(cv);
mOldBase = mOldName = oldName;
mNewBase = mNewName = newName;
@@ -66,71 +56,6 @@ public class RenameClassAdapter extends ClassVisitor {
assert (mOldBase == null && mNewBase == null) || (mOldBase != null && mNewBase != null);
}
-
- /**
- * Renames a type descriptor, e.g. "Lcom.package.MyClass;"
- * If the type doesn't need to be renamed, returns the input string as-is.
- */
- String renameTypeDesc(String desc) {
- if (desc == null) {
- return null;
- }
-
- return renameType(Type.getType(desc));
- }
-
- /**
- * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
- * object element, e.g. "[Lcom.package.MyClass;"
- * If the type doesn't need to be renamed, returns the internal name of the input type.
- */
- String renameType(Type type) {
- if (type == null) {
- return null;
- }
-
- if (type.getSort() == Type.OBJECT) {
- String in = type.getInternalName();
- return "L" + renameInternalType(in) + ";";
- } else if (type.getSort() == Type.ARRAY) {
- StringBuilder sb = new StringBuilder();
- for (int n = type.getDimensions(); n > 0; n--) {
- sb.append('[');
- }
- sb.append(renameType(type.getElementType()));
- return sb.toString();
- }
- return type.getDescriptor();
- }
-
- /**
- * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an
- * object element, e.g. "[Lcom.package.MyClass;".
- * This is like renameType() except that it returns a Type object.
- * If the type doesn't need to be renamed, returns the input type object.
- */
- Type renameTypeAsType(Type type) {
- if (type == null) {
- return null;
- }
-
- if (type.getSort() == Type.OBJECT) {
- String in = type.getInternalName();
- String newIn = renameInternalType(in);
- if (newIn != in) {
- return Type.getType("L" + newIn + ";");
- }
- } else if (type.getSort() == Type.ARRAY) {
- StringBuilder sb = new StringBuilder();
- for (int n = type.getDimensions(); n > 0; n--) {
- sb.append('[');
- }
- sb.append(renameType(type.getElementType()));
- return Type.getType(sb.toString());
- }
- return type;
- }
-
/**
* Renames an internal type name, e.g. "com.package.MyClass".
* If the type doesn't need to be renamed, returns the input string as-is.
@@ -138,7 +63,8 @@ public class RenameClassAdapter extends ClassVisitor {
* The internal type of some of the MethodVisitor turns out to be a type
descriptor sometimes so descriptors are renamed too.
*/
- String renameInternalType(String type) {
+ @Override
+ protected String renameInternalType(String type) {
if (type == null) {
return null;
}
@@ -155,309 +81,7 @@ public class RenameClassAdapter extends ClassVisitor {
if (pos == mOldBase.length() && type.startsWith(mOldBase)) {
return mNewBase + type.substring(pos);
}
-
- // The internal type of some of the MethodVisitor turns out to be a type
- // descriptor sometimes. This is the case with visitTypeInsn(type) and
- // visitMethodInsn(owner). We try to detect it and adjust it here.
- if (type.indexOf(';') > 0) {
- type = renameTypeDesc(type);
- }
-
return type;
}
- /**
- * Renames a method descriptor, i.e. applies renameType to all arguments and to the
- * return value.
- */
- String renameMethodDesc(String desc) {
- if (desc == null) {
- return null;
- }
-
- Type[] args = Type.getArgumentTypes(desc);
-
- StringBuilder sb = new StringBuilder("(");
- for (Type arg : args) {
- String name = renameType(arg);
- sb.append(name);
- }
- sb.append(')');
-
- Type ret = Type.getReturnType(desc);
- String name = renameType(ret);
- sb.append(name);
-
- return sb.toString();
- }
-
-
- /**
- * Renames the ClassSignature handled by ClassVisitor.visit
- * or the MethodTypeSignature handled by ClassVisitor.visitMethod.
- */
- String renameTypeSignature(String sig) {
- if (sig == null) {
- return null;
- }
- SignatureReader reader = new SignatureReader(sig);
- SignatureWriter writer = new SignatureWriter();
- reader.accept(new RenameSignatureAdapter(writer));
- sig = writer.toString();
- return sig;
- }
-
-
- /**
- * Renames the FieldTypeSignature handled by ClassVisitor.visitField
- * or MethodVisitor.visitLocalVariable.
- */
- String renameFieldSignature(String sig) {
- if (sig == null) {
- return null;
- }
- SignatureReader reader = new SignatureReader(sig);
- SignatureWriter writer = new SignatureWriter();
- reader.acceptType(new RenameSignatureAdapter(writer));
- sig = writer.toString();
- return sig;
- }
-
-
- //----------------------------------
- // Methods from the ClassAdapter
-
- @Override
- public void visit(int version, int access, String name, String signature,
- String superName, String[] interfaces) {
- name = renameInternalType(name);
- superName = renameInternalType(superName);
- signature = renameTypeSignature(signature);
-
- super.visit(version, access, name, signature, superName, interfaces);
- }
-
- @Override
- public void visitInnerClass(String name, String outerName, String innerName, int access) {
- assert outerName.equals(mOldName);
- outerName = renameInternalType(outerName);
- name = outerName + "$" + innerName;
- super.visitInnerClass(name, outerName, innerName, access);
- }
-
- @Override
- public MethodVisitor visitMethod(int access, String name, String desc,
- String signature, String[] exceptions) {
- desc = renameMethodDesc(desc);
- signature = renameTypeSignature(signature);
- MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
- return new RenameMethodAdapter(mw);
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- desc = renameTypeDesc(desc);
- return super.visitAnnotation(desc, visible);
- }
-
- @Override
- public FieldVisitor visitField(int access, String name, String desc,
- String signature, Object value) {
- desc = renameTypeDesc(desc);
- signature = renameFieldSignature(signature);
- return super.visitField(access, name, desc, signature, value);
- }
-
-
- //----------------------------------
-
- /**
- * A method visitor that renames all references from an old class name to a new class name.
- */
- public class RenameMethodAdapter extends MethodVisitor {
-
- /**
- * Creates a method visitor that renames all references from a given old name to a given new
- * name. The method visitor will also rename all inner classes.
- * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
- */
- public RenameMethodAdapter(MethodVisitor mv) {
- super(Opcodes.ASM4, mv);
- }
-
- @Override
- public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- desc = renameTypeDesc(desc);
-
- return super.visitAnnotation(desc, visible);
- }
-
- @Override
- public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
- desc = renameTypeDesc(desc);
-
- return super.visitParameterAnnotation(parameter, desc, visible);
- }
-
- @Override
- public void visitTypeInsn(int opcode, String type) {
- type = renameInternalType(type);
-
- super.visitTypeInsn(opcode, type);
- }
-
- @Override
- public void visitFieldInsn(int opcode, String owner, String name, String desc) {
- owner = renameInternalType(owner);
- desc = renameTypeDesc(desc);
-
- super.visitFieldInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitMethodInsn(int opcode, String owner, String name, String desc) {
- owner = renameInternalType(owner);
- desc = renameMethodDesc(desc);
-
- super.visitMethodInsn(opcode, owner, name, desc);
- }
-
- @Override
- public void visitLdcInsn(Object cst) {
- // If cst is a Type, this means the code is trying to pull the .class constant
- // for this class, so it needs to be renamed too.
- if (cst instanceof Type) {
- cst = renameTypeAsType((Type) cst);
- }
- super.visitLdcInsn(cst);
- }
-
- @Override
- public void visitMultiANewArrayInsn(String desc, int dims) {
- desc = renameTypeDesc(desc);
-
- super.visitMultiANewArrayInsn(desc, dims);
- }
-
- @Override
- public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
- type = renameInternalType(type);
-
- super.visitTryCatchBlock(start, end, handler, type);
- }
-
- @Override
- public void visitLocalVariable(String name, String desc, String signature,
- Label start, Label end, int index) {
- desc = renameTypeDesc(desc);
- signature = renameFieldSignature(signature);
-
- super.visitLocalVariable(name, desc, signature, start, end, index);
- }
-
- }
-
- //----------------------------------
-
- public class RenameSignatureAdapter extends SignatureVisitor {
-
- private final SignatureVisitor mSv;
-
- public RenameSignatureAdapter(SignatureVisitor sv) {
- super(Opcodes.ASM4);
- mSv = sv;
- }
-
- @Override
- public void visitClassType(String name) {
- name = renameInternalType(name);
- mSv.visitClassType(name);
- }
-
- @Override
- public void visitInnerClassType(String name) {
- name = renameInternalType(name);
- mSv.visitInnerClassType(name);
- }
-
- @Override
- public SignatureVisitor visitArrayType() {
- SignatureVisitor sv = mSv.visitArrayType();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public void visitBaseType(char descriptor) {
- mSv.visitBaseType(descriptor);
- }
-
- @Override
- public SignatureVisitor visitClassBound() {
- SignatureVisitor sv = mSv.visitClassBound();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public void visitEnd() {
- mSv.visitEnd();
- }
-
- @Override
- public SignatureVisitor visitExceptionType() {
- SignatureVisitor sv = mSv.visitExceptionType();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public void visitFormalTypeParameter(String name) {
- mSv.visitFormalTypeParameter(name);
- }
-
- @Override
- public SignatureVisitor visitInterface() {
- SignatureVisitor sv = mSv.visitInterface();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public SignatureVisitor visitInterfaceBound() {
- SignatureVisitor sv = mSv.visitInterfaceBound();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public SignatureVisitor visitParameterType() {
- SignatureVisitor sv = mSv.visitParameterType();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public SignatureVisitor visitReturnType() {
- SignatureVisitor sv = mSv.visitReturnType();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public SignatureVisitor visitSuperclass() {
- SignatureVisitor sv = mSv.visitSuperclass();
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public void visitTypeArgument() {
- mSv.visitTypeArgument();
- }
-
- @Override
- public SignatureVisitor visitTypeArgument(char wildcard) {
- SignatureVisitor sv = mSv.visitTypeArgument(wildcard);
- return new RenameSignatureAdapter(sv);
- }
-
- @Override
- public void visitTypeVariable(String name) {
- mSv.visitTypeVariable(name);
- }
-
- }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java
new file mode 100644
index 000000000000..ed2c128e1900
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.java;
+
+/**
+ * Defines the same interface as the java.lang.AutoCloseable which was added in
+ * Java 7. This hack makes it possible to run the Android code which uses Java 7
+ * features (API 18 and beyond) to run on Java 6.
+ * <p/>
+ * Extracted from API level 18, file:
+ * platform/libcore/luni/src/main/java/java/lang/AutoCloseable.java
+ */
+public interface AutoCloseable {
+ /**
+ * Closes the object and release any system resources it holds.
+ */
+ void close() throws Exception; }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/Charsets.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/Charsets.java
new file mode 100644
index 000000000000..f73b06b5ffba
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/Charsets.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.java;
+
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Defines the same class as the java.nio.charset.Charsets which was added in
+ * Dalvik VM. This hack, provides a replacement for that class which can't be
+ * loaded in the standard JVM since it's in the java package and standard JVM
+ * doesn't have it. An implementation of the native methods in the original
+ * class has been added.
+ * <p/>
+ * Extracted from API level 18, file:
+ * platform/libcore/luni/src/main/java/java/nio/charset/Charsets
+ */
+public final class Charsets {
+ /**
+ * A cheap and type-safe constant for the ISO-8859-1 Charset.
+ */
+ public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+
+ /**
+ * A cheap and type-safe constant for the US-ASCII Charset.
+ */
+ public static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+ /**
+ * A cheap and type-safe constant for the UTF-8 Charset.
+ */
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /**
+ * Returns a new byte array containing the bytes corresponding to the given characters,
+ * encoded in US-ASCII. Unrepresentable characters are replaced by (byte) '?'.
+ */
+ public static byte[] toAsciiBytes(char[] chars, int offset, int length) {
+ CharBuffer cb = CharBuffer.allocate(length);
+ cb.put(chars, offset, length);
+ return US_ASCII.encode(cb).array();
+ }
+
+ /**
+ * Returns a new byte array containing the bytes corresponding to the given characters,
+ * encoded in ISO-8859-1. Unrepresentable characters are replaced by (byte) '?'.
+ */
+ public static byte[] toIsoLatin1Bytes(char[] chars, int offset, int length) {
+ CharBuffer cb = CharBuffer.allocate(length);
+ cb.put(chars, offset, length);
+ return ISO_8859_1.encode(cb).array();
+ }
+
+ /**
+ * Returns a new byte array containing the bytes corresponding to the given characters,
+ * encoded in UTF-8. All characters are representable in UTF-8.
+ */
+ public static byte[] toUtf8Bytes(char[] chars, int offset, int length) {
+ CharBuffer cb = CharBuffer.allocate(length);
+ cb.put(chars, offset, length);
+ return UTF_8.encode(cb).array();
+ }
+
+ /**
+ * Returns a new byte array containing the bytes corresponding to the given characters,
+ * encoded in UTF-16BE. All characters are representable in UTF-16BE.
+ */
+ public static byte[] toBigEndianUtf16Bytes(char[] chars, int offset, int length) {
+ byte[] result = new byte[length * 2];
+ int end = offset + length;
+ int resultIndex = 0;
+ for (int i = offset; i < end; ++i) {
+ char ch = chars[i];
+ result[resultIndex++] = (byte) (ch >> 8);
+ result[resultIndex++] = (byte) ch;
+ }
+ return result;
+ }
+
+ /**
+ * Decodes the given US-ASCII bytes into the given char[]. Equivalent to but faster than:
+ *
+ * for (int i = 0; i < count; ++i) {
+ * char ch = (char) (data[start++] & 0xff);
+ * value[i] = (ch <= 0x7f) ? ch : REPLACEMENT_CHAR;
+ * }
+ */
+ public static void asciiBytesToChars(byte[] bytes, int offset, int length, char[] chars) {
+ if (bytes == null || chars == null) {
+ return;
+ }
+ final char REPLACEMENT_CHAR = (char)0xffd;
+ int start = offset;
+ for (int i = 0; i < length; ++i) {
+ char ch = (char) (bytes[start++] & 0xff);
+ chars[i] = (ch <= 0x7f) ? ch : REPLACEMENT_CHAR;
+ }
+ }
+
+ /**
+ * Decodes the given ISO-8859-1 bytes into the given char[]. Equivalent to but faster than:
+ *
+ * for (int i = 0; i < count; ++i) {
+ * value[i] = (char) (data[start++] & 0xff);
+ * }
+ */
+ public static void isoLatin1BytesToChars(byte[] bytes, int offset, int length, char[] chars) {
+ if (bytes == null || chars == null) {
+ return;
+ }
+ int start = offset;
+ for (int i = 0; i < length; ++i) {
+ chars[i] = (char) (bytes[start++] & 0xff);
+ }
+ }
+
+ private Charsets() {
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/IntegralToString.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/IntegralToString.java
new file mode 100644
index 000000000000..e6dd00a76f52
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/IntegralToString.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.java;
+
+/**
+ * Defines the same class as the java.lang.IntegralToString which was added in
+ * Dalvik VM. This hack, provides a replacement for that class which can't be
+ * loaded in the standard JVM since it's in the java package and standard JVM
+ * doesn't have it. Since it's no longer in java.lang, access to package
+ * private methods and classes has been replaced by the closes matching public
+ * implementation.
+ * <p/>
+ * Extracted from API level 18, file:
+ * platform/libcore/luni/src/main/java/java/lang/IntegralToString.java
+ */
+public final class IntegralToString {
+ /**
+ * When appending to an AbstractStringBuilder, this thread-local char[] lets us avoid
+ * allocation of a temporary array. (We can't write straight into the AbstractStringBuilder
+ * because it's almost as expensive to work out the exact length of the result as it is to
+ * do the formatting. We could try being conservative and "delete"-ing the unused space
+ * afterwards, but then we'd need to duplicate convertInt and convertLong rather than share
+ * the code.)
+ */
+ private static final ThreadLocal<char[]> BUFFER = new ThreadLocal<char[]>() {
+ @Override protected char[] initialValue() {
+ return new char[20]; // Maximum length of a base-10 long.
+ }
+ };
+
+ /**
+ * These tables are used to special-case toString computation for
+ * small values. This serves three purposes: it reduces memory usage;
+ * it increases performance for small values; and it decreases the
+ * number of comparisons required to do the length computation.
+ * Elements of this table are lazily initialized on first use.
+ * No locking is necessary, i.e., we use the non-volatile, racy
+ * single-check idiom.
+ */
+ private static final String[] SMALL_NONNEGATIVE_VALUES = new String[100];
+ private static final String[] SMALL_NEGATIVE_VALUES = new String[100];
+
+ /** TENS[i] contains the tens digit of the number i, 0 <= i <= 99. */
+ private static final char[] TENS = {
+ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
+ '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
+ '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
+ '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
+ '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
+ '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
+ '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
+ '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
+ '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
+ '9', '9', '9', '9', '9', '9', '9', '9', '9', '9'
+ };
+
+ /** Ones [i] contains the tens digit of the number i, 0 <= i <= 99. */
+ private static final char[] ONES = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ };
+
+ /**
+ * Table for MOD / DIV 10 computation described in Section 10-21
+ * of Hank Warren's "Hacker's Delight" online addendum.
+ * http://www.hackersdelight.org/divcMore.pdf
+ */
+ private static final char[] MOD_10_TABLE = {
+ 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 0
+ };
+
+ /**
+ * The digits for every supported radix.
+ */
+ private static final char[] DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z'
+ };
+
+ private static final char[] UPPER_CASE_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z'
+ };
+
+ private IntegralToString() {
+ }
+
+ /**
+ * Equivalent to Integer.toString(i, radix).
+ */
+ public static String intToString(int i, int radix) {
+ if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+ radix = 10;
+ }
+ if (radix == 10) {
+ return intToString(i);
+ }
+
+ /*
+ * If i is positive, negate it. This is the opposite of what one might
+ * expect. It is necessary because the range of the negative values is
+ * strictly larger than that of the positive values: there is no
+ * positive value corresponding to Integer.MIN_VALUE.
+ */
+ boolean negative = false;
+ if (i < 0) {
+ negative = true;
+ } else {
+ i = -i;
+ }
+
+ int bufLen = radix < 8 ? 33 : 12; // Max chars in result (conservative)
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ int q = i / radix;
+ buf[--cursor] = DIGITS[radix * q - i];
+ i = q;
+ } while (i != 0);
+
+ if (negative) {
+ buf[--cursor] = '-';
+ }
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ /**
+ * Equivalent to Integer.toString(i).
+ */
+ public static String intToString(int i) {
+ return convertInt(null, i);
+ }
+
+ /**
+ * Equivalent to sb.append(Integer.toString(i)).
+ */
+ public static void appendInt(StringBuilder sb, int i) {
+ convertInt(sb, i);
+ }
+
+ /**
+ * Returns the string representation of i and leaves sb alone if sb is null.
+ * Returns null and appends the string representation of i to sb if sb is non-null.
+ */
+ private static String convertInt(StringBuilder sb, int i) {
+ boolean negative = false;
+ String quickResult = null;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ if (i < 100) {
+ if (i < 0) {
+ // If -n is still negative, n is Integer.MIN_VALUE
+ quickResult = "-2147483648";
+ } else {
+ quickResult = SMALL_NEGATIVE_VALUES[i];
+ if (quickResult == null) {
+ SMALL_NEGATIVE_VALUES[i] = quickResult =
+ i < 10 ? stringOf('-', ONES[i]) : stringOf('-', TENS[i], ONES[i]);
+ }
+ }
+ }
+ } else {
+ if (i < 100) {
+ quickResult = SMALL_NONNEGATIVE_VALUES[i];
+ if (quickResult == null) {
+ SMALL_NONNEGATIVE_VALUES[i] = quickResult =
+ i < 10 ? stringOf(ONES[i]) : stringOf(TENS[i], ONES[i]);
+ }
+ }
+ }
+ if (quickResult != null) {
+ if (sb != null) {
+ sb.append(quickResult);
+ return null;
+ }
+ return quickResult;
+ }
+
+ int bufLen = 11; // Max number of chars in result
+ char[] buf = (sb != null) ? BUFFER.get() : new char[bufLen];
+ int cursor = bufLen;
+
+ // Calculate digits two-at-a-time till remaining digits fit in 16 bits
+ while (i >= (1 << 16)) {
+ // Compute q = n/100 and r = n % 100 as per "Hacker's Delight" 10-8
+ int q = (int) ((0x51EB851FL * i) >>> 37);
+ int r = i - 100*q;
+ buf[--cursor] = ONES[r];
+ buf[--cursor] = TENS[r];
+ i = q;
+ }
+
+ // Calculate remaining digits one-at-a-time for performance
+ while (i != 0) {
+ // Compute q = n/10 and r = n % 10 as per "Hacker's Delight" 10-8
+ int q = (0xCCCD * i) >>> 19;
+ int r = i - 10*q;
+ buf[--cursor] = DIGITS[r];
+ i = q;
+ }
+
+ if (negative) {
+ buf[--cursor] = '-';
+ }
+
+ if (sb != null) {
+ sb.append(buf, cursor, bufLen - cursor);
+ return null;
+ } else {
+ return new String(buf, cursor, bufLen - cursor);
+ }
+ }
+
+ /**
+ * Equivalent to Long.toString(v, radix).
+ */
+ public static String longToString(long v, int radix) {
+ int i = (int) v;
+ if (i == v) {
+ return intToString(i, radix);
+ }
+
+ if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+ radix = 10;
+ }
+ if (radix == 10) {
+ return longToString(v);
+ }
+
+ /*
+ * If v is positive, negate it. This is the opposite of what one might
+ * expect. It is necessary because the range of the negative values is
+ * strictly larger than that of the positive values: there is no
+ * positive value corresponding to Integer.MIN_VALUE.
+ */
+ boolean negative = false;
+ if (v < 0) {
+ negative = true;
+ } else {
+ v = -v;
+ }
+
+ int bufLen = radix < 8 ? 65 : 23; // Max chars in result (conservative)
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ long q = v / radix;
+ buf[--cursor] = DIGITS[(int) (radix * q - v)];
+ v = q;
+ } while (v != 0);
+
+ if (negative) {
+ buf[--cursor] = '-';
+ }
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ /**
+ * Equivalent to Long.toString(l).
+ */
+ public static String longToString(long l) {
+ return convertLong(null, l);
+ }
+
+ /**
+ * Equivalent to sb.append(Long.toString(l)).
+ */
+ public static void appendLong(StringBuilder sb, long l) {
+ convertLong(sb, l);
+ }
+
+ /**
+ * Returns the string representation of n and leaves sb alone if sb is null.
+ * Returns null and appends the string representation of n to sb if sb is non-null.
+ */
+ private static String convertLong(StringBuilder sb, long n) {
+ int i = (int) n;
+ if (i == n) {
+ return convertInt(sb, i);
+ }
+
+ boolean negative = (n < 0);
+ if (negative) {
+ n = -n;
+ if (n < 0) {
+ // If -n is still negative, n is Long.MIN_VALUE
+ String quickResult = "-9223372036854775808";
+ if (sb != null) {
+ sb.append(quickResult);
+ return null;
+ }
+ return quickResult;
+ }
+ }
+
+ int bufLen = 20; // Maximum number of chars in result
+ char[] buf = (sb != null) ? BUFFER.get() : new char[bufLen];
+
+ int low = (int) (n % 1000000000); // Extract low-order 9 digits
+ int cursor = intIntoCharArray(buf, bufLen, low);
+
+ // Zero-pad Low order part to 9 digits
+ while (cursor != (bufLen - 9)) {
+ buf[--cursor] = '0';
+ }
+
+ /*
+ * The remaining digits are (n - low) / 1,000,000,000. This
+ * "exact division" is done as per the online addendum to Hank Warren's
+ * "Hacker's Delight" 10-20, http://www.hackersdelight.org/divcMore.pdf
+ */
+ n = ((n - low) >>> 9) * 0x8E47CE423A2E9C6DL;
+
+ /*
+ * If the remaining digits fit in an int, emit them using a
+ * single call to intIntoCharArray. Otherwise, strip off the
+ * low-order digit, put it in buf, and then call intIntoCharArray
+ * on the remaining digits (which now fit in an int).
+ */
+ if ((n & (-1L << 32)) == 0) {
+ cursor = intIntoCharArray(buf, cursor, (int) n);
+ } else {
+ /*
+ * Set midDigit to n % 10
+ */
+ int lo32 = (int) n;
+ int hi32 = (int) (n >>> 32);
+
+ // midDigit = ((unsigned) low32) % 10, per "Hacker's Delight" 10-21
+ int midDigit = MOD_10_TABLE[(0x19999999 * lo32 + (lo32 >>> 1) + (lo32 >>> 3)) >>> 28];
+
+ // Adjust midDigit for hi32. (assert hi32 == 1 || hi32 == 2)
+ midDigit -= hi32 << 2; // 1L << 32 == -4 MOD 10
+ if (midDigit < 0) {
+ midDigit += 10;
+ }
+ buf[--cursor] = DIGITS[midDigit];
+
+ // Exact division as per Warren 10-20
+ int rest = ((int) ((n - midDigit) >>> 1)) * 0xCCCCCCCD;
+ cursor = intIntoCharArray(buf, cursor, rest);
+ }
+
+ if (negative) {
+ buf[--cursor] = '-';
+ }
+ if (sb != null) {
+ sb.append(buf, cursor, bufLen - cursor);
+ return null;
+ } else {
+ return new String(buf, cursor, bufLen - cursor);
+ }
+ }
+
+ /**
+ * Inserts the unsigned decimal integer represented by n into the specified
+ * character array starting at position cursor. Returns the index after
+ * the last character inserted (i.e., the value to pass in as cursor the
+ * next time this method is called). Note that n is interpreted as a large
+ * positive integer (not a negative integer) if its sign bit is set.
+ */
+ private static int intIntoCharArray(char[] buf, int cursor, int n) {
+ // Calculate digits two-at-a-time till remaining digits fit in 16 bits
+ while ((n & 0xffff0000) != 0) {
+ /*
+ * Compute q = n/100 and r = n % 100 as per "Hacker's Delight" 10-8.
+ * This computation is slightly different from the corresponding
+ * computation in intToString: the shifts before and after
+ * multiply can't be combined, as that would yield the wrong result
+ * if n's sign bit were set.
+ */
+ int q = (int) ((0x51EB851FL * (n >>> 2)) >>> 35);
+ int r = n - 100*q;
+ buf[--cursor] = ONES[r];
+ buf[--cursor] = TENS[r];
+ n = q;
+ }
+
+ // Calculate remaining digits one-at-a-time for performance
+ while (n != 0) {
+ // Compute q = n / 10 and r = n % 10 as per "Hacker's Delight" 10-8
+ int q = (0xCCCD * n) >>> 19;
+ int r = n - 10*q;
+ buf[--cursor] = DIGITS[r];
+ n = q;
+ }
+ return cursor;
+ }
+
+ public static String intToBinaryString(int i) {
+ int bufLen = 32; // Max number of binary digits in an int
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[i & 1];
+ } while ((i >>>= 1) != 0);
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ public static String longToBinaryString(long v) {
+ int i = (int) v;
+ if (v >= 0 && i == v) {
+ return intToBinaryString(i);
+ }
+
+ int bufLen = 64; // Max number of binary digits in a long
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[((int) v) & 1];
+ } while ((v >>>= 1) != 0);
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ public static StringBuilder appendByteAsHex(StringBuilder sb, byte b, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
+ sb.append(digits[(b >> 4) & 0xf]);
+ sb.append(digits[b & 0xf]);
+ return sb;
+ }
+
+ public static String byteToHexString(byte b, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
+ char[] buf = new char[2]; // We always want two digits.
+ buf[0] = digits[(b >> 4) & 0xf];
+ buf[1] = digits[b & 0xf];
+ return new String(buf, 0, 2);
+ }
+
+ public static String bytesToHexString(byte[] bytes, boolean upperCase) {
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
+ char[] buf = new char[bytes.length * 2];
+ int c = 0;
+ for (byte b : bytes) {
+ buf[c++] = digits[(b >> 4) & 0xf];
+ buf[c++] = digits[b & 0xf];
+ }
+ return new String(buf);
+ }
+
+ public static String intToHexString(int i, boolean upperCase, int minWidth) {
+ int bufLen = 8; // Max number of hex digits in an int
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
+ do {
+ buf[--cursor] = digits[i & 0xf];
+ } while ((i >>>= 4) != 0 || (bufLen - cursor < minWidth));
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ public static String longToHexString(long v) {
+ int i = (int) v;
+ if (v >= 0 && i == v) {
+ return intToHexString(i, false, 0);
+ }
+
+ int bufLen = 16; // Max number of hex digits in a long
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[((int) v) & 0xF];
+ } while ((v >>>= 4) != 0);
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ public static String intToOctalString(int i) {
+ int bufLen = 11; // Max number of octal digits in an int
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[i & 7];
+ } while ((i >>>= 3) != 0);
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ public static String longToOctalString(long v) {
+ int i = (int) v;
+ if (v >= 0 && i == v) {
+ return intToOctalString(i);
+ }
+ int bufLen = 22; // Max number of octal digits in a long
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[((int) v) & 7];
+ } while ((v >>>= 3) != 0);
+
+ return new String(buf, cursor, bufLen - cursor);
+ }
+
+ private static String stringOf(char... args) {
+ return new String(args, 0, args.length);
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/UnsafeByteSequence.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/UnsafeByteSequence.java
new file mode 100644
index 000000000000..0e09080c5111
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/UnsafeByteSequence.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 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 com.android.tools.layoutlib.java;
+
+import java.nio.charset.Charset;
+
+/**
+ * Defines the same class as the java.lang.UnsafeByteSequence which was added in
+ * Dalvik VM. This hack, provides a replacement for that class which can't be
+ * loaded in the standard JVM since it's in the java package and standard JVM
+ * doesn't have it.
+ * <p/>
+ * Extracted from API level 18, file:
+ * platform/libcore/luni/src/main/java/java/lang/UnsafeByteSequence.java
+ */
+public class UnsafeByteSequence {
+ private byte[] bytes;
+ private int count;
+
+ public UnsafeByteSequence(int initialCapacity) {
+ this.bytes = new byte[initialCapacity];
+ }
+
+ public int size() {
+ return count;
+ }
+
+ /**
+ * Moves the write pointer back to the beginning of the sequence,
+ * but without resizing or reallocating the buffer.
+ */
+ public void rewind() {
+ count = 0;
+ }
+
+ public void write(byte[] buffer, int offset, int length) {
+ if (count + length >= bytes.length) {
+ byte[] newBytes = new byte[(count + length) * 2];
+ System.arraycopy(bytes, 0, newBytes, 0, count);
+ bytes = newBytes;
+ }
+ System.arraycopy(buffer, offset, bytes, count, length);
+ count += length;
+ }
+
+ public void write(int b) {
+ if (count == bytes.length) {
+ byte[] newBytes = new byte[count * 2];
+ System.arraycopy(bytes, 0, newBytes, 0, count);
+ bytes = newBytes;
+ }
+ bytes[count++] = (byte) b;
+ }
+
+ public byte[] toByteArray() {
+ if (count == bytes.length) {
+ return bytes;
+ }
+ byte[] result = new byte[count];
+ System.arraycopy(bytes, 0, result, 0, count);
+ return result;
+ }
+
+ public String toString(Charset cs) {
+ return new String(bytes, 0, count, cs);
+ }
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index d6dba6a9fb34..005fc9dadab4 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -31,7 +31,9 @@ import org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.TreeMap;
/**
@@ -51,8 +53,10 @@ public class AsmAnalyzerTest {
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
+ Set<String> excludeClasses = new HashSet<String>(1);
+ excludeClasses.add("java.lang.JavaClass");
mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
- null /* deriveFrom */, null /* includeGlobs */ );
+ null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
}
@After
@@ -64,6 +68,7 @@ public class AsmAnalyzerTest {
Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
assertArrayEquals(new String[] {
+ "java.lang.JavaClass",
"mock_android.dummy.InnerTest",
"mock_android.dummy.InnerTest$DerivingClass",
"mock_android.dummy.InnerTest$MyGenerics1",
@@ -221,7 +226,11 @@ public class AsmAnalyzerTest {
for (ClassReader cr2 : in_deps.values()) {
cr2.accept(visitor, 0 /* flags */);
}
+ keep.putAll(new_keep);
assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
+ assertArrayEquals(new String[] {
+ "mock_android.widget.TableLayout",
+ }, keep.keySet().toArray());
}
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 7b76a5b2f914..8a27173181a3 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -19,16 +19,29 @@ package com.android.tools.layoutlib.create;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
* Unit tests for some methods of {@link AsmGenerator}.
@@ -40,6 +53,9 @@ public class AsmGeneratorTest {
private String mOsDestJar;
private File mTempFile;
+ // ASM internal name for the the class in java package that should be refactored.
+ private static final String JAVA_CLASS_NAME = "java/lang/JavaClass";
+
@Before
public void setUp() throws Exception {
mLog = new MockLog();
@@ -48,7 +64,7 @@ public class AsmGeneratorTest {
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
- mTempFile = File.createTempFile("mock", "jar");
+ mTempFile = File.createTempFile("mock", ".jar");
mOsDestJar = mTempFile.getAbsolutePath();
mTempFile.deleteOnExit();
}
@@ -97,6 +113,11 @@ public class AsmGeneratorTest {
}
@Override
+ public String[] getJavaPkgClasses() {
+ return new String[0];
+ }
+
+ @Override
public String[] getDeleteReturns() {
// methods deleted from their return type.
return new String[0];
@@ -109,11 +130,201 @@ public class AsmGeneratorTest {
null, // derived from
new String[] { // include classes
"**"
- });
+ },
+ new HashSet<String>(0) /* excluded classes */);
aa.analyze();
agen.generate();
Set<String> notRenamed = agen.getClassesNotRenamed();
assertArrayEquals(new String[] { "not/an/actual/ClassName" }, notRenamed.toArray());
+
+ }
+
+ @Test
+ public void testClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new ICreateInfo() {
+ @Override
+ public Class<?>[] getInjectedClasses() {
+ // classes to inject in the final JAR
+ return new Class<?>[] {
+ com.android.tools.layoutlib.create.dataclass.JavaClass.class
+ };
+ }
+
+ @Override
+ public String[] getDelegateMethods() {
+ return new String[0];
+ }
+
+ @Override
+ public String[] getDelegateClassNatives() {
+ return new String[0];
+ }
+
+ @Override
+ public String[] getOverriddenMethods() {
+ // methods to force override
+ return new String[0];
+ }
+
+ @Override
+ public String[] getRenamedClasses() {
+ // classes to rename (so that we can replace them)
+ return new String[0];
+ }
+
+ @Override
+ public String[] getJavaPkgClasses() {
+ // classes to refactor (so that we can replace them)
+ return new String[] {
+ "java.lang.JavaClass", "com.android.tools.layoutlib.create.dataclass.JavaClass",
+ };
+ }
+
+ @Override
+ public String[] getDeleteReturns() {
+ // methods deleted from their return type.
+ return new String[0];
+ }
+ };
+
+ AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
+
+ AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+ null, // derived from
+ new String[] { // include classes
+ "**"
+ },
+ new HashSet<String>(1));
+ aa.analyze();
+ agen.generate();
+ Map<String, ClassReader> output = parseZip(mOsDestJar);
+ boolean injectedClassFound = false;
+ for (ClassReader cr: output.values()) {
+ TestClassVisitor cv = new TestClassVisitor();
+ cr.accept(cv, 0);
+ injectedClassFound |= cv.mInjectedClassFound;
+ }
+ assertTrue(injectedClassFound);
+ }
+
+ private Map<String,ClassReader> parseZip(String jarPath) throws IOException {
+ TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+
+ ZipFile zip = new ZipFile(jarPath);
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ ZipEntry entry;
+ while (entries.hasMoreElements()) {
+ entry = entries.nextElement();
+ if (entry.getName().endsWith(".class")) {
+ ClassReader cr = new ClassReader(zip.getInputStream(entry));
+ String className = classReaderToClassName(cr);
+ classes.put(className, cr);
+ }
+ }
+
+ return classes;
+ }
+
+ private String classReaderToClassName(ClassReader classReader) {
+ if (classReader == null) {
+ return null;
+ } else {
+ return classReader.getClassName().replace('/', '.');
+ }
+ }
+
+ private class TestClassVisitor extends ClassVisitor {
+
+ boolean mInjectedClassFound = false;
+
+ TestClassVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ assertTrue(!getBase(name).equals(JAVA_CLASS_NAME));
+ if (name.equals("com/android/tools/layoutlib/create/dataclass/JavaClass")) {
+ mInjectedClassFound = true;
+ }
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc,
+ String signature, Object value) {
+ assertTrue(testType(Type.getType(desc)));
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ @SuppressWarnings("hiding")
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ return new MethodVisitor(Opcodes.ASM4, mv) {
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name,
+ String desc) {
+ assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
+ assertTrue(testType(Type.getType(desc)));
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst) {
+ if (cst instanceof Type) {
+ assertTrue(testType((Type)cst));
+ }
+ super.visitLdcInsn(cst);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ assertTrue(!getBase(type).equals(JAVA_CLASS_NAME));
+ super.visitTypeInsn(opcode, type);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name,
+ String desc) {
+ assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
+ assertTrue(testType(Type.getType(desc)));
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ };
+ }
+
+ private boolean testType(Type type) {
+ int sort = type.getSort();
+ if (sort == Type.OBJECT) {
+ assertTrue(!getBase(type.getInternalName()).equals(JAVA_CLASS_NAME));
+ } else if (sort == Type.ARRAY) {
+ assertTrue(!getBase(type.getElementType().getInternalName())
+ .equals(JAVA_CLASS_NAME));
+ } else if (sort == Type.METHOD) {
+ boolean r = true;
+ for (Type t : type.getArgumentTypes()) {
+ r &= testType(t);
+ }
+ return r & testType(type.getReturnType());
+ }
+ return true;
+ }
+
+ private String getBase(String className) {
+ if (className == null) {
+ return null;
+ }
+ int pos = className.indexOf('$');
+ if (pos > 0) {
+ return className.substring(0, pos);
+ }
+ return className;
+ }
}
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java
index 90c6a9c9ac7c..6211e73417e4 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java
@@ -24,7 +24,7 @@ import org.junit.Before;
import org.junit.Test;
/**
- *
+ *
*/
public class RenameClassAdapterTest {
@@ -36,10 +36,10 @@ public class RenameClassAdapterTest {
mOuter = new RenameClassAdapter(null, // cv
"com.pack.Old",
"org.blah.New");
-
+
mInner = new RenameClassAdapter(null, // cv
"com.pack.Old$Inner",
- "org.blah.New$Inner");
+ "org.blah.New$Inner");
}
@After
@@ -72,7 +72,7 @@ public class RenameClassAdapterTest {
// arrays
assertEquals("[Lorg.blah.New;", mOuter.renameTypeDesc("[Lcom.pack.Old;"));
assertEquals("[[Lorg.blah.New;", mOuter.renameTypeDesc("[[Lcom.pack.Old;"));
-
+
assertEquals("[Lorg.blah.New;", mInner.renameTypeDesc("[Lcom.pack.Old;"));
assertEquals("[[Lorg.blah.New;", mInner.renameTypeDesc("[[Lcom.pack.Old;"));
}
@@ -93,10 +93,6 @@ public class RenameClassAdapterTest {
*/
@Test
public void testRenameInternalType() {
- // a descriptor is not left untouched
- assertEquals("Lorg.blah.New;", mOuter.renameInternalType("Lcom.pack.Old;"));
- assertEquals("Lorg.blah.New$Inner;", mOuter.renameInternalType("Lcom.pack.Old$Inner;"));
-
// an actual FQCN
assertEquals("org.blah.New", mOuter.renameInternalType("com.pack.Old"));
assertEquals("org.blah.New$Inner", mOuter.renameInternalType("com.pack.Old$Inner"));
@@ -115,6 +111,6 @@ public class RenameClassAdapterTest {
mOuter.renameMethodDesc("(IDLcom.pack.Old;[Lcom.pack.Old$Inner;)Lcom.pack.Old$Other;"));
}
-
+
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/JavaClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/JavaClass.java
new file mode 100644
index 000000000000..9b5a91886b84
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/JavaClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 com.android.tools.layoutlib.create.dataclass;
+
+public final class JavaClass {
+
+ public static final String test = "test";
+}
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index a7ea74f4adf2..60d8efb1bb99 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/data/mock_android.jardesc b/tools/layoutlib/create/tests/data/mock_android.jardesc
deleted file mode 100644
index 95f7591d7046..000000000000
--- a/tools/layoutlib/create/tests/data/mock_android.jardesc
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?>
-<jardesc>
- <jar path="C:/ralf/google/src/raphael-lapdroid/device/tools/layoutlib/create/tests/data/mock_android.jar"/>
- <options buildIfNeeded="true" compress="true" descriptionLocation="/layoutlib_create/tests/data/mock_android.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
- <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
- <selectedProjects/>
- <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
- <sealing sealJar="false">
- <packagesToSeal/>
- <packagesToUnSeal/>
- </sealing>
- </manifest>
- <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
- <javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.widget"/>
- <javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.view"/>
- <javaElement handleIdentifier="=layoutlib_create/tests&lt;mock_android.dummy"/>
- </selectedElements>
-</jardesc>
diff --git a/tools/layoutlib/create/tests/mock_data/java/lang/JavaClass.java b/tools/layoutlib/create/tests/mock_data/java/lang/JavaClass.java
new file mode 100644
index 000000000000..59612e95d354
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/java/lang/JavaClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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 java.lang;
+
+public class JavaClass {
+
+ public static String test = "test";
+}
diff --git a/tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java b/tools/layoutlib/create/tests/mock_data/mock_android/dummy/InnerTest.java
index e355ead16a7d..d3a1d05b98fd 100644
--- a/tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/dummy/InnerTest.java
@@ -19,6 +19,7 @@ package mock_android.dummy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
public class InnerTest {
@@ -66,13 +67,13 @@ public class InnerTest {
}
}
- public <X> void genericMethod1(X a, X[] a) {
+ public <X> void genericMethod1(X a, X[] b) {
}
public <X, Y> void genericMethod2(X a, List<Y> b) {
}
- public <X, Y> void genericMethod3(X a, List<Y extends InnerTest> b) {
+ public <X, Y extends InnerTest> void genericMethod3(X a, List<Y> b) {
}
public <T extends InnerTest> void genericMethod4(T[] a, Collection<T> b, Collection<?> c) {
@@ -85,6 +86,6 @@ public class InnerTest {
mInnerInstance = m;
mTheIntEnum = null;
mGeneric1 = new MyGenerics1();
- genericMethod(new DerivingClass[0], new ArrayList<DerivingClass>(), new ArrayList<InnerTest>());
+ genericMethod4(new DerivingClass[0], new ArrayList<DerivingClass>(), new ArrayList<InnerTest>());
}
}
diff --git a/tools/layoutlib/create/tests/mock_android/view/View.java b/tools/layoutlib/create/tests/mock_data/mock_android/view/View.java
index a80a98daf1d4..84ec8a9d9094 100644
--- a/tools/layoutlib/create/tests/mock_android/view/View.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/view/View.java
@@ -16,6 +16,10 @@
package mock_android.view;
+import java.lang.JavaClass;
+
public class View {
+ String x = JavaClass.test;
+
}
diff --git a/tools/layoutlib/create/tests/mock_android/view/ViewGroup.java b/tools/layoutlib/create/tests/mock_data/mock_android/view/ViewGroup.java
index 466470fc1537..466470fc1537 100644
--- a/tools/layoutlib/create/tests/mock_android/view/ViewGroup.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/view/ViewGroup.java
diff --git a/tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
index 3870a63d9782..3870a63d9782 100644
--- a/tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
diff --git a/tools/layoutlib/create/tests/mock_android/widget/TableLayout.java b/tools/layoutlib/create/tests/mock_data/mock_android/widget/TableLayout.java
index e455e7d61fd3..e455e7d61fd3 100644
--- a/tools/layoutlib/create/tests/mock_android/widget/TableLayout.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/widget/TableLayout.java
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index dd57ae662ee9..ad8de6943043 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -20,7 +20,8 @@ LOCAL_CFLAGS := -Wall -Werror
LOCAL_STATIC_LIBRARIES := \
libutils \
libandroidfw \
- libcutils
+ libcutils \
+ liblog
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -ldl -lpthread
diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java
index f557365694ea..ca0291bb9a67 100644
--- a/tools/preload/Policy.java
+++ b/tools/preload/Policy.java
@@ -69,6 +69,7 @@ public class Policy {
// Threads
"android.os.AsyncTask",
"android.pim.ContactsAsyncHelper",
+ "android.webkit.WebViewClassic$1",
"java.lang.ProcessManager"
));
diff --git a/tools/preload/Record.java b/tools/preload/Record.java
index 14e9201ff1c1..d0a2af4d7965 100644
--- a/tools/preload/Record.java
+++ b/tools/preload/Record.java
@@ -42,14 +42,24 @@ class Record {
"com.android.fakeoemfeatures\\u003Abackground",
"com.android.fakeoemfeatures:core",
"com.android.fakeoemfeatures\\u003Acore",
+ "com.android.launcher:wallpaper_chooser",
+ "com.android.launcher\\u003Awallpaper_chooser",
+ "com.android.nfc:handover",
+ "com.android.nfc\\u003Ahandover",
"com.google.android.music:main",
"com.google.android.music\\u003Amain",
"com.google.android.music:ui",
"com.google.android.music\\u003Aui",
"com.google.android.setupwarlock:broker",
"com.google.android.setupwarlock\\u003Abroker",
+ "mobi.mgeek.TunnyBrowser:DolphinNotification",
+ "mobi.mgeek.TunnyBrowser\\u003ADolphinNotification",
+ "com.qo.android.sp.oem:Quickword",
+ "com.qo.android.sp.oem\\u003AQuickword",
"android:ui",
"android\\u003Aui",
+ "system:ui",
+ "system\\u003Aui",
};
enum Type {
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
index fce2e931125e..90fbc08e9a54 100644
--- a/tools/validatekeymaps/Android.mk
+++ b/tools/validatekeymaps/Android.mk
@@ -20,7 +20,8 @@ LOCAL_CFLAGS := -Wall -Werror
LOCAL_STATIC_LIBRARIES := \
libandroidfw \
libutils \
- libcutils
+ libcutils \
+ liblog
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -ldl -lpthread