summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/Command.cpp5
-rw-r--r--tools/aapt/Package.cpp33
-rw-r--r--tools/aapt/Resource.cpp89
-rw-r--r--tools/aapt/ResourceTable.cpp25
-rw-r--r--tools/aapt/ResourceTable.h6
-rw-r--r--tools/aapt/StringPool.cpp2
-rw-r--r--tools/aapt/ZipFile.h2
-rw-r--r--tools/layoutlib/bridge/resources/bars/action_bar.xml9
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.pngbin0 -> 3900 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.pngbin0 -> 3991 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.pngbin0 -> 3140 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml24
-rw-r--r--tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java59
-rw-r--r--tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java104
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java8
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java7
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java23
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java46
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java14
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java6
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java23
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java83
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java7
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java14
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java10
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java31
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java14
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java164
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java15
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java18
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java57
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java47
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java54
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java170
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java48
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java440
-rw-r--r--tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java186
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java5
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java1
-rw-r--r--tools/orientationplot/README.txt87
-rwxr-xr-xtools/orientationplot/orientationplot.py451
-rw-r--r--tools/preload/Record.java22
-rw-r--r--tools/validatekeymaps/Android.mk34
-rw-r--r--tools/validatekeymaps/Main.cpp129
52 files changed, 2261 insertions, 342 deletions
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 739763e..8ac7590 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -198,8 +198,10 @@ int doList(Bundle* bundle)
if (&res == NULL) {
printf("\nNo resource table found.\n");
} else {
+#ifndef HAVE_ANDROID_OS
printf("\nResource table:\n");
res.print(false);
+#endif
}
Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -428,8 +430,9 @@ int doDump(Bundle* bundle)
}
if (strcmp("resources", option) == 0) {
+#ifndef HAVE_ANDROID_OS
res.print(bundle->getValues());
-
+#endif
} else if (strcmp("xmltree", option) == 0) {
if (bundle->getFileSpecCount() < 3) {
fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 999a5cf..ab71f34 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -33,8 +33,8 @@ static const char* kNoCompressExt[] = {
/* fwd decls, so I can write this downward */
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip,
- const sp<AaptDir>& dir, const AaptGroupEntry& ge);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
+ const AaptGroupEntry& ge, const ResourceFilter* filter);
bool processFile(Bundle* bundle, ZipFile* zip,
const sp<AaptGroup>& group, const sp<AaptFile>& file);
bool okayToCompress(Bundle* bundle, const String8& pathName);
@@ -204,34 +204,45 @@ ssize_t processAssets(Bundle* bundle, ZipFile* zip,
const size_t N = assets->getGroupEntries().size();
for (size_t i=0; i<N; i++) {
const AaptGroupEntry& ge = assets->getGroupEntries()[i];
- if (!filter.match(ge.toParams())) {
- continue;
- }
- ssize_t res = processAssets(bundle, zip, assets, ge);
+
+ ssize_t res = processAssets(bundle, zip, assets, ge, &filter);
if (res < 0) {
return res;
}
+
count += res;
}
return count;
}
-ssize_t processAssets(Bundle* bundle, ZipFile* zip,
- const sp<AaptDir>& dir, const AaptGroupEntry& ge)
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
+ const AaptGroupEntry& ge, const ResourceFilter* filter)
{
ssize_t count = 0;
const size_t ND = dir->getDirs().size();
size_t i;
for (i=0; i<ND; i++) {
- ssize_t res = processAssets(bundle, zip, dir->getDirs().valueAt(i), ge);
+ const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
+
+ const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0;
+
+ if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) {
+ continue;
+ }
+
+ ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL);
if (res < 0) {
return res;
}
count += res;
}
+ if (filter != NULL && !filter->match(ge.toParams())) {
+ return count;
+ }
+
const size_t NF = dir->getFiles().size();
for (i=0; i<NF; i++) {
sp<AaptGroup> gp = dir->getFiles().valueAt(i);
@@ -441,7 +452,7 @@ ssize_t processJarFile(ZipFile* jar, ZipFile* out)
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip)
{
- ssize_t err;
+ status_t err;
ssize_t count = 0;
const android::Vector<const char*>& jars = bundle->getJarFiles();
@@ -450,7 +461,7 @@ ssize_t processJarFiles(Bundle* bundle, ZipFile* zip)
ZipFile jar;
err = jar.open(jars[i], ZipFile::kOpenReadOnly);
if (err != 0) {
- fprintf(stderr, "ERROR: unable to open '%s' as a zip file: %zd\n",
+ fprintf(stderr, "ERROR: unable to open '%s' as a zip file: %d\n",
jars[i], err);
return err;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 0a4f24f..730bd71 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -148,9 +148,10 @@ private:
bool isValidResourceType(const String8& type)
{
- return type == "anim" || type == "drawable" || type == "layout"
+ return type == "anim" || type == "animator" || type == "interpolator"
+ || type == "drawable" || type == "layout"
|| type == "values" || type == "xml" || type == "raw"
- || type == "color" || type == "menu";
+ || type == "color" || type == "menu" || type == "mipmap";
}
static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true)
@@ -284,9 +285,9 @@ static status_t makeFileResources(Bundle* bundle, const sp<AaptAssets>& assets,
}
static status_t preProcessImages(Bundle* bundle, const sp<AaptAssets>& assets,
- const sp<ResourceTypeSet>& set)
+ const sp<ResourceTypeSet>& set, const char* type)
{
- ResourceDirIterator it(set, String8("drawable"));
+ ResourceDirIterator it(set, String8(type));
Vector<sp<AaptFile> > newNameFiles;
Vector<String8> newNamePaths;
bool hasErrors = false;
@@ -542,11 +543,11 @@ static bool applyFileOverlay(Bundle *bundle,
DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > baseFiles =
baseGroup->getFiles();
for (size_t i=0; i < baseFiles.size(); i++) {
- printf("baseFile %ld has flavor %s\n", i,
+ printf("baseFile %zd has flavor %s\n", i,
baseFiles.keyAt(i).toString().string());
}
for (size_t i=0; i < overlayFiles.size(); i++) {
- printf("overlayFile %ld has flavor %s\n", i,
+ printf("overlayFile %zd has flavor %s\n", i,
overlayFiles.keyAt(i).toString().string());
}
}
@@ -560,7 +561,7 @@ static bool applyFileOverlay(Bundle *bundle,
keyAt(overlayGroupIndex));
if(baseFileIndex < UNKNOWN_ERROR) {
if (bundle->getVerbose()) {
- printf("found a match (%ld) for overlay file %s, for flavor %s\n",
+ printf("found a match (%zd) for overlay file %s, for flavor %s\n",
baseFileIndex,
overlayGroup->getLeaf().string(),
overlayFiles.keyAt(overlayGroupIndex).toString().string());
@@ -798,18 +799,24 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
sp<ResourceTypeSet> drawables;
sp<ResourceTypeSet> layouts;
sp<ResourceTypeSet> anims;
+ sp<ResourceTypeSet> animators;
+ sp<ResourceTypeSet> interpolators;
sp<ResourceTypeSet> xmls;
sp<ResourceTypeSet> raws;
sp<ResourceTypeSet> colors;
sp<ResourceTypeSet> menus;
+ sp<ResourceTypeSet> mipmaps;
ASSIGN_IT(drawable);
ASSIGN_IT(layout);
ASSIGN_IT(anim);
+ ASSIGN_IT(animator);
+ ASSIGN_IT(interpolator);
ASSIGN_IT(xml);
ASSIGN_IT(raw);
ASSIGN_IT(color);
ASSIGN_IT(menu);
+ ASSIGN_IT(mipmap);
assets->setResources(resources);
// now go through any resource overlays and collect their files
@@ -825,10 +832,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
if (!applyFileOverlay(bundle, assets, &drawables, "drawable") ||
!applyFileOverlay(bundle, assets, &layouts, "layout") ||
!applyFileOverlay(bundle, assets, &anims, "anim") ||
+ !applyFileOverlay(bundle, assets, &animators, "animator") ||
+ !applyFileOverlay(bundle, assets, &interpolators, "interpolator") ||
!applyFileOverlay(bundle, assets, &xmls, "xml") ||
!applyFileOverlay(bundle, assets, &raws, "raw") ||
!applyFileOverlay(bundle, assets, &colors, "color") ||
- !applyFileOverlay(bundle, assets, &menus, "menu")) {
+ !applyFileOverlay(bundle, assets, &menus, "menu") ||
+ !applyFileOverlay(bundle, assets, &mipmaps, "mipmap")) {
return UNKNOWN_ERROR;
}
@@ -836,7 +846,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
if (drawables != NULL) {
if (bundle->getOutputAPKFile() != NULL) {
- err = preProcessImages(bundle, assets, drawables);
+ err = preProcessImages(bundle, assets, drawables, "drawable");
}
if (err == NO_ERROR) {
err = makeFileResources(bundle, assets, &table, drawables, "drawable");
@@ -848,6 +858,20 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
}
}
+ if (mipmaps != NULL) {
+ if (bundle->getOutputAPKFile() != NULL) {
+ err = preProcessImages(bundle, assets, mipmaps, "mipmap");
+ }
+ if (err == NO_ERROR) {
+ err = makeFileResources(bundle, assets, &table, mipmaps, "mipmap");
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ } else {
+ hasErrors = true;
+ }
+ }
+
if (layouts != NULL) {
err = makeFileResources(bundle, assets, &table, layouts, "layout");
if (err != NO_ERROR) {
@@ -862,6 +886,20 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
}
}
+ if (animators != NULL) {
+ err = makeFileResources(bundle, assets, &table, animators, "animator");
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (interpolators != NULL) {
+ err = makeFileResources(bundle, assets, &table, interpolators, "interpolator");
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
if (xmls != NULL) {
err = makeFileResources(bundle, assets, &table, xmls, "xml");
if (err != NO_ERROR) {
@@ -969,6 +1007,36 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
err = NO_ERROR;
}
+ if (animators != NULL) {
+ ResourceDirIterator it(animators, String8("animator"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
+ hasErrors = true;
+ }
+ err = NO_ERROR;
+ }
+
+ if (interpolators != NULL) {
+ ResourceDirIterator it(interpolators, String8("interpolator"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
+ hasErrors = true;
+ }
+ err = NO_ERROR;
+ }
+
if (xmls != NULL) {
ResourceDirIterator it(xmls, String8("xml"));
while ((err=it.next()) == NO_ERROR) {
@@ -2088,12 +2156,13 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
// tag:attribute pairs that should be checked in layout files.
KeyedVector<String8, NamespaceAttributePair> kLayoutTagAttrPairs;
addTagAttrPair(&kLayoutTagAttrPairs, "view", NULL, "class");
+ addTagAttrPair(&kLayoutTagAttrPairs, "fragment", NULL, "class");
addTagAttrPair(&kLayoutTagAttrPairs, "fragment", RESOURCES_ANDROID_NAMESPACE, "name");
// tag:attribute pairs that should be checked in xml files.
KeyedVector<String8, NamespaceAttributePair> kXmlTagAttrPairs;
addTagAttrPair(&kXmlTagAttrPairs, "PreferenceScreen", RESOURCES_ANDROID_NAMESPACE, "fragment");
- addTagAttrPair(&kXmlTagAttrPairs, "Header", RESOURCES_ANDROID_NAMESPACE, "fragment");
+ addTagAttrPair(&kXmlTagAttrPairs, "header", RESOURCES_ANDROID_NAMESPACE, "fragment");
const Vector<sp<AaptDir> >& dirs = assets->resDirs();
const size_t K = dirs.size();
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 818c3c6..5339566 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2444,7 +2444,7 @@ ResourceTable::validateLocalizations(void)
if (configSet.count(defaultLocale) == 0) {
fprintf(stdout, "aapt: warning: string '%s' has no default translation in %s; found:",
String8(nameIter->first).string(), mBundle->getResourceSourceDirs()[0]);
- for (set<String8>::iterator locales = configSet.begin();
+ for (set<String8>::const_iterator locales = configSet.begin();
locales != configSet.end();
locales++) {
fprintf(stdout, " %s", (*locales).string());
@@ -2555,7 +2555,7 @@ ResourceFilter::parse(const char* arg)
}
bool
-ResourceFilter::match(int axis, uint32_t value)
+ResourceFilter::match(int axis, uint32_t value) const
{
if (value == 0) {
// they didn't specify anything so take everything
@@ -2571,7 +2571,7 @@ ResourceFilter::match(int axis, uint32_t value)
}
bool
-ResourceFilter::match(const ResTable_config& config)
+ResourceFilter::match(const ResTable_config& config) const
{
if (config.locale) {
uint32_t locale = (config.country[1] << 24) | (config.country[0] << 16)
@@ -2624,6 +2624,8 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
const size_t N = mOrderedPackages.size();
size_t pi;
+ const static String16 mipmap16("mipmap");
+
bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
// Iterate through all data, collecting all values (strings,
@@ -2646,7 +2648,10 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
typeStrings.add(String16("<empty>"), false);
continue;
}
- typeStrings.add(t->getName(), false);
+ const String16 typeName(t->getName());
+ typeStrings.add(typeName, false);
+
+ const bool filterable = (typeName != mipmap16);
const size_t N = t->getOrderedConfigs().size();
for (size_t ci=0; ci<N; ci++) {
@@ -2657,7 +2662,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
const size_t N = c->getEntries().size();
for (size_t ei=0; ei<N; ei++) {
ConfigDescription config = c->getEntries().keyAt(ei);
- if (!filter.match(config)) {
+ if (filterable && !filter.match(config)) {
continue;
}
sp<Entry> e = c->getEntries().valueAt(ei);
@@ -2737,6 +2742,8 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
"Type name %s not found",
String8(typeName).string());
+ const bool filterable = (typeName != mipmap16);
+
const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
// First write the typeSpec chunk, containing information about
@@ -2761,7 +2768,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
(((uint8_t*)data->editData())
+ typeSpecStart + sizeof(ResTable_typeSpec));
memset(typeSpecFlags, 0, sizeof(uint32_t)*N);
-
+
for (size_t ei=0; ei<N; ei++) {
sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
if (cl->getPublic()) {
@@ -2769,11 +2776,11 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
}
const size_t CN = cl->getEntries().size();
for (size_t ci=0; ci<CN; ci++) {
- if (!filter.match(cl->getEntries().keyAt(ci))) {
+ if (filterable && !filter.match(cl->getEntries().keyAt(ci))) {
continue;
}
for (size_t cj=ci+1; cj<CN; cj++) {
- if (!filter.match(cl->getEntries().keyAt(cj))) {
+ if (filterable && !filter.match(cl->getEntries().keyAt(cj))) {
continue;
}
typeSpecFlags[ei] |= htodl(
@@ -2810,7 +2817,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
config.screenWidth,
config.screenHeight));
- if (!filter.match(config)) {
+ if (filterable && !filter.match(config)) {
continue;
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 186c7ca..bbb8140 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -549,9 +549,9 @@ class ResourceFilter
public:
ResourceFilter() : mData(), mContainsPseudo(false) {}
status_t parse(const char* arg);
- bool match(int axis, uint32_t value);
- bool match(const ResTable_config& config);
- inline bool containsPseudo() { return mContainsPseudo; }
+ bool match(int axis, uint32_t value) const;
+ bool match(const ResTable_config& config) const;
+ inline bool containsPseudo() const { return mContainsPseudo; }
private:
KeyedVector<int,SortedVector<uint32_t> > mData;
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index a09cec0..d067d59 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -30,7 +30,7 @@ void printStringPool(const ResStringPool* pool)
str = String8(pool->stringAt(s, &len)).string();
}
- printf("String #%ld: %s\n", s, str);
+ printf("String #%zd: %s\n", s, str);
}
}
diff --git a/tools/aapt/ZipFile.h b/tools/aapt/ZipFile.h
index dbbd072..7877550 100644
--- a/tools/aapt/ZipFile.h
+++ b/tools/aapt/ZipFile.h
@@ -57,7 +57,7 @@ public:
/*
* Open a new or existing archive.
*/
- typedef enum {
+ enum {
kOpenReadOnly = 0x01,
kOpenReadWrite = 0x02,
kOpenCreate = 0x04, // create if it doesn't exist
diff --git a/tools/layoutlib/bridge/resources/bars/action_bar.xml b/tools/layoutlib/bridge/resources/bars/action_bar.xml
new file mode 100644
index 0000000..51983f2
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/action_bar.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..4bcd2be
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..cfeba3e
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..1d97e05
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml b/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
new file mode 100644
index 0000000..c5acddb
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:layout_marginRight="15dip"/>
+</merge>
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
new file mode 100644
index 0000000..7b444aa
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 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.animation;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.animation.PropertyValuesHolder
+ *
+ * Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ * The main goal of this class' methods are to provide a native way to access setters and getters
+ * on some object. In this case we want to default to using Java reflection instead so the native
+ * methods do nothing.
+ *
+ */
+/*package*/ class PropertyValuesHolder_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
+ // do nothing
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
new file mode 100644
index 0000000..aabd3f1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 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.app;
+
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Fragment}
+ *
+ * Through the layoutlib_create tool, the original methods of Fragment have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * The methods being re-implemented are the ones responsible for instantiating Fragment objects.
+ * Because the classes of these objects are found in the project, these methods need access to
+ * {@link IProjectCallback} object. They are however static methods, so the callback is set
+ * before the inflation through {@link #setProjectCallback(IProjectCallback)}.
+ */
+public class Fragment_Delegate {
+
+ private static IProjectCallback sProjectCallback;
+
+ /**
+ * Sets the current {@link IProjectCallback} to be used to instantiate classes coming
+ * from the project being rendered.
+ */
+ public static void setProjectCallback(IProjectCallback projectCallback) {
+ sProjectCallback = projectCallback;
+ }
+
+ /**
+ * Like {@link #instantiate(Context, String, Bundle)} but with a null
+ * argument Bundle.
+ */
+ @LayoutlibDelegate
+ /*package*/ static Fragment instantiate(Context context, String fname) {
+ return instantiate(context, fname, null);
+ }
+
+ /**
+ * Create a new instance of a Fragment with the given class name. This is
+ * the same as calling its empty constructor.
+ *
+ * @param context The calling context being used to instantiate the fragment.
+ * This is currently just used to get its ClassLoader.
+ * @param fname The class name of the fragment to instantiate.
+ * @param args Bundle of arguments to supply to the fragment, which it
+ * can retrieve with {@link #getArguments()}. May be null.
+ * @return Returns a new fragment instance.
+ * @throws InstantiationException If there is a failure in instantiating
+ * the given fragment class. This is a runtime exception; it is not
+ * normally expected to happen.
+ */
+ @LayoutlibDelegate
+ /*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
+ try {
+ if (sProjectCallback != null) {
+ Fragment f = (Fragment) sProjectCallback.loadView(fname,
+ new Class[0], new Object[0]);
+
+ if (args != null) {
+ args.setClassLoader(f.getClass().getClassLoader());
+ f.mArguments = args;
+ }
+ return f;
+ }
+
+ return null;
+ } catch (ClassNotFoundException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (java.lang.InstantiationException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (IllegalAccessException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (Exception e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 9c86e80..080b85f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -136,17 +136,20 @@ import java.io.InputStream;
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
Rect padding, Options opts) {
+ opts.inBitmap = null;
return null;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
+ opts.inBitmap = null;
return null;
}
@LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
int length, Options opts) {
+ opts.inBitmap = null;
return null;
}
@@ -156,4 +159,9 @@ import java.io.InputStream;
// BitmapFactory.finishDecode();
return chunk;
}
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
+ return true;
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 8eb0693..9a8cf04 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -79,6 +79,13 @@ public class BitmapShader_Delegate extends Shader_Delegate {
return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate(int native_shader, int native_bitmap,
+ int shaderTileModeX, int shaderTileModeY) {
+ // pass, not needed.
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
private BitmapShader_Delegate(java.awt.image.BufferedImage image,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 87c3eb6..66e59d8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -62,6 +62,8 @@ public final class Bitmap_Delegate {
private final Config mConfig;
private BufferedImage mImage;
private boolean mHasAlpha = true;
+ private int mGenerationId = 0;
+
// ---- Public Helper methods ----
@@ -184,6 +186,15 @@ public final class Bitmap_Delegate {
return mHasAlpha && mConfig != Config.RGB_565;
}
+ /**
+ * Update the generationId.
+ *
+ * @see Bitmap#getGenerationId()
+ */
+ public void change() {
+ mGenerationId++;
+ }
+
// ---- native methods ----
@LayoutlibDelegate
@@ -384,6 +395,16 @@ public final class Bitmap_Delegate {
}
@LayoutlibDelegate
+ /*package*/ static int nativeGenerationId(int nativeBitmap) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mGenerationId;
+ }
+
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
// This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
// used during aidl call so really this should not be called.
@@ -504,7 +525,7 @@ public final class Bitmap_Delegate {
int nativeInt = sManager.addNewDelegate(delegate);
// and create/return a new Bitmap with it
- return new Bitmap(nativeInt, isMutable, null /*ninePatchChunk*/, density);
+ 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 02a2ddf..4decd1a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -270,13 +270,6 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void drawText(Canvas thisCanvas,
- String text, float x, float y, Paint paint) {
- native_drawText(thisCanvas.mNativeCanvas, text, 0, text.length(), x, y,
- paint.mNativePaint);
- }
-
- @LayoutlibDelegate
/*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
Paint paint) {
// FIXME
@@ -330,12 +323,6 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int initGL() {
- // not supported.
- return 0;
- }
-
- @LayoutlibDelegate
/*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -353,11 +340,6 @@ public final class Canvas_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nativeSetViewport(int nCanvas, int w, int h) {
- // only useful in GL which is not supported, so no need to do anything.
- }
-
- @LayoutlibDelegate
/*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
int paint, int layerFlags) {
// get the delegate from the native int.
@@ -962,7 +944,7 @@ 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 paint) {
+ final float startX, final float startY, int flags, int paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
@@ -1062,12 +1044,30 @@ public final class Canvas_Delegate {
@LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
- float y, int paint) {
+ float y, int flags, int paint) {
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
- native_drawText(nativeCanvas, buffer, 0, count, x, y, paint);
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextRun(int nativeCanvas, String text,
+ int start, int end, int contextStart, int contextEnd,
+ float x, float y, int flags, int paint) {
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
+ int start, int count, int contextStart, int contextCount,
+ float x, float y, int flags, int paint) {
+ native_drawText(nativeCanvas, text, start, count, x, y, flags, paint);
}
@LayoutlibDelegate
@@ -1094,7 +1094,7 @@ public final class Canvas_Delegate {
char[] text, int index,
int count, int path,
float hOffset,
- float vOffset,
+ float vOffset, int bidiFlags,
int paint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1106,7 +1106,7 @@ public final class Canvas_Delegate {
String text, int path,
float hOffset,
float vOffset,
- int paint) {
+ int flags, int paint) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Canvas.drawTextOnPath is not supported.", null, null /*data*/);
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index 4c692c2..e5a7ab6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -56,7 +56,7 @@ public abstract class ColorFilter_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void finalizer(int native_instance) {
+ /*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
sManager.removeJavaReferenceFor(native_instance);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index d4c5b8d..2de344b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -60,5 +60,11 @@ public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
+ /*package*/ static int nColorMatrixFilter(int nativeFilter, float[] array) {
+ // pass
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
index fcc12d7..f6e1d00 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -78,6 +78,20 @@ public class ComposeShader_Delegate extends Shader_Delegate {
return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, int native_skiaShaderA,
+ int native_skiaShaderB, int native_mode) {
+ // pass, not needed.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, int native_skiaShaderA,
+ int native_skiaShaderB, int porterDuffMode) {
+ // pass, not needed.
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index 3afe965..0ee883d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -60,5 +60,11 @@ public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
+ /*package*/ static int nCreateLightingFilter(int nativeFilter, int mul, int add) {
+ // pass
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index a735ea1..a2ba758 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -54,7 +54,7 @@ public final class LinearGradient_Delegate extends Gradient_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static int nativeCreate1(
+ /*package*/ static int nativeCreate1(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode) {
LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
@@ -63,13 +63,30 @@ public final class LinearGradient_Delegate extends Gradient_Delegate {
}
@LayoutlibDelegate
- /*package*/ static int nativeCreate2(
+ /*package*/ static int nativeCreate2(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode) {
- return nativeCreate1(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
+ return nativeCreate1(thisGradient,
+ x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
tileMode);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(LinearGradient thisGradient,
+ int native_shader, float x0, float y0, float x1, float y1,
+ int colors[], float positions[], int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(LinearGradient thisGradient,
+ int native_shader, float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
/**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index d4cf1f6..373f482 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -23,6 +23,7 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.FontMetricsInt;
+import android.text.TextUtils;
import java.awt.BasicStroke;
import java.awt.Font;
@@ -89,6 +90,7 @@ public class Paint_Delegate {
private MaskFilter_Delegate mMaskFilter;
private Rasterizer_Delegate mRasterizer;
+
// ---- Public Helper methods ----
public static Paint_Delegate getDelegate(int native_paint) {
@@ -391,7 +393,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void setShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
int color) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -938,7 +940,82 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_getTextPath(int native_object,
+ /*package*/ static float native_getTextRunAdvances(int native_object,
+ char[] text, int index, int count, int contextIndex, int contextCount,
+ int flags, float[] advances, int advancesIndex) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0.f;
+ }
+
+ 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;
+
+ }
+
+ @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) {
+ // FIXME: support contextStart, contextEnd and direction flag
+ 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);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
+ int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
+ int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
char[] text, int index, int count, float x, float y, int path) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -946,7 +1023,7 @@ public class Paint_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void native_getTextPath(int native_object,
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
String text, int start, int end, float x, float y, int path) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 65c65a1..c45dbaa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -60,5 +60,12 @@ public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
+ /*package*/ static int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
+ int porterDuffMode) {
+ // pass
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index bdc0ab1..9bf78b4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -68,6 +68,20 @@ public class RadialGradient_Delegate extends Gradient_Delegate {
tileMode);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
+ int colors[], float positions[], int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
+ int color0, int color1, int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
/**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index b0ee5c2..cb31b8f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -469,6 +469,16 @@ public class Region_Delegate {
return region1.mArea.equals(region2.mArea);
}
+ @LayoutlibDelegate
+ /*package*/ static String nativeToString(int native_region) {
+ Region_Delegate region = sManager.getDelegate(native_region);
+ if (region == null) {
+ return "not found";
+ }
+
+ return region.mArea.toString();
+ }
+
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index c6dd54b..368c0384 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -76,38 +76,13 @@ public abstract class Shader_Delegate {
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void nativeDestructor(int native_shader) {
+ /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
sManager.removeJavaReferenceFor(native_shader);
}
@LayoutlibDelegate
- /*package*/ static boolean nativeGetLocalMatrix(int native_shader, int matrix_instance) {
- // get the delegate from the native int.
- Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
- if (shaderDelegate == null) {
- return false;
- }
-
- // get the (optional) out matrix.
- Matrix_Delegate outMatrixDelegate = Matrix_Delegate.getDelegate(matrix_instance);
-
- if (shaderDelegate.mLocalMatrix == null || shaderDelegate.mLocalMatrix.isIdentity()) {
- if (outMatrixDelegate != null) {
- outMatrixDelegate.reset();
- }
- return false;
- }
-
- if (outMatrixDelegate != null) {
- outMatrixDelegate.set(shaderDelegate.mLocalMatrix);
- }
-
- return true;
- }
-
-
- @LayoutlibDelegate
- /*package*/ static void nativeSetLocalMatrix(int native_shader, int matrix_instance) {
+ /*package*/ static void nativeSetLocalMatrix(int native_shader, int native_skiaShader,
+ int matrix_instance) {
// get the delegate from the native int.
Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
if (shaderDelegate == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index f70f9cf..966e06e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -62,6 +62,20 @@ public class SweepGradient_Delegate extends Gradient_Delegate {
return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
}
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, float cx, float cy,
+ int[] colors, float[] positions) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, float cx, float cy,
+ int color0, int color1) {
+ // nothing to be done here.
+ return 0;
+ }
+
// ---- Private delegate/helper methods ----
/**
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index d5266a5..0f3cf57 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -22,10 +22,7 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
-import android.util.Xml;
import java.io.IOException;
@@ -35,131 +32,66 @@ import java.io.IOException;
* Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced
* by calls to methods of the same name in this delegate class.
*
- * Generally we don't want to copy-paste a huge method like that just for one small features,
- * but because this is done after this platform is final and the next version (Honeycomb) has a
- * better mechanism (or slightly less copy-paste), maintenance of this duplicated code is not
- * a problem.
- *
*/
public class LayoutInflater_Delegate {
+ /**
+ * Recursive method used to descend down the xml hierarchy and instantiate
+ * views, instantiate their children, and then call onFinishInflate().
+ */
@LayoutlibDelegate
- /*package*/ static void parseInclude(LayoutInflater thisInflater,
- XmlPullParser parser, View parent, AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ /*package*/ static void rInflate(LayoutInflater thisInflater,
+ XmlPullParser parser, View parent, final AttributeSet attrs,
+ boolean finishInflate) throws XmlPullParserException, IOException {
+
+ if (finishInflate == false) {
+ // this is a merge rInflate!
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(true);
+ }
+ }
+
+ // ---- START DEFAULT IMPLEMENTATION.
+ final int depth = parser.getDepth();
int type;
- if (parent instanceof ViewGroup) {
- final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
- if (layout == 0) {
- final String value = attrs.getAttributeValue(null, "layout");
- if (value == null) {
- throw new InflateException("You must specifiy a layout in the"
- + " include tag: <include layout=\"@layout/layoutID\" />");
- } else {
- throw new InflateException("You must specifiy a valid layout "
- + "reference. The layout ID " + value + " is not valid.");
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String name = parser.getName();
+
+ if (LayoutInflater.TAG_REQUEST_FOCUS.equals(name)) {
+ thisInflater.parseRequestFocus(parser, parent);
+ } else if (LayoutInflater.TAG_INCLUDE.equals(name)) {
+ if (parser.getDepth() == 0) {
+ throw new InflateException("<include /> cannot be the root element");
}
+ thisInflater.parseInclude(parser, parent, attrs);
+ } else if (LayoutInflater.TAG_MERGE.equals(name)) {
+ throw new InflateException("<merge /> must be the root element");
} else {
- final XmlResourceParser childParser =
- thisInflater.getContext().getResources().getLayout(layout);
-
- try {
- final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
-
- while ((type = childParser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty.
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(childParser.getPositionDescription() +
- ": No start tag found!");
- }
-
- final String childName = childParser.getName();
-
- if (LayoutInflater.TAG_MERGE.equals(childName)) {
- // ---- START MODIFICATIONS ----
- if (thisInflater instanceof BridgeInflater) {
- ((BridgeInflater) thisInflater).setIsInMerge(true);
- }
- // ---- END MODIFICATIONS ----
-
- // Inflate all children.
- thisInflater.rInflate(childParser, parent, childAttrs);
-
- // ---- START MODIFICATIONS ----
- if (thisInflater instanceof BridgeInflater) {
- ((BridgeInflater) thisInflater).setIsInMerge(false);
- }
- // ---- END MODIFICATIONS ----
- } else {
- final View view = thisInflater.createViewFromTag(childName, childAttrs);
- final ViewGroup group = (ViewGroup) parent;
-
- // We try to load the layout params set in the <include /> tag. If
- // they don't exist, we will rely on the layout params set in the
- // included XML file.
- // During a layoutparams generation, a runtime exception is thrown
- // if either layout_width or layout_height is missing. We catch
- // this exception and set localParams accordingly: true means we
- // successfully loaded layout params from the <include /> tag,
- // false means we need to rely on the included layout params.
- ViewGroup.LayoutParams params = null;
- try {
- params = group.generateLayoutParams(attrs);
- } catch (RuntimeException e) {
- params = group.generateLayoutParams(childAttrs);
- } finally {
- if (params != null) {
- view.setLayoutParams(params);
- }
- }
-
- // Inflate all children.
- thisInflater.rInflate(childParser, view, childAttrs);
-
- // Attempt to override the included layout's android:id with the
- // one set on the <include /> tag itself.
- TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.View, 0, 0);
- int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
- // While we're at it, let's try to override android:visibility.
- int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
- a.recycle();
-
- if (id != View.NO_ID) {
- view.setId(id);
- }
-
- switch (visibility) {
- case 0:
- view.setVisibility(View.VISIBLE);
- break;
- case 1:
- view.setVisibility(View.INVISIBLE);
- break;
- case 2:
- view.setVisibility(View.GONE);
- break;
- }
-
- group.addView(view);
- }
- } finally {
- childParser.close();
- }
+ final View view = thisInflater.createViewFromTag(parent, name, attrs);
+ final ViewGroup viewGroup = (ViewGroup) parent;
+ final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
+ thisInflater.rInflate(parser, view, attrs, true);
+ viewGroup.addView(view, params);
}
- } else {
- throw new InflateException("<include /> can only be used inside of a ViewGroup");
}
- final int currentDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
- // Empty
+ if (finishInflate) parent.onFinishInflate();
+
+ // ---- END DEFAULT IMPLEMENTATION.
+
+ if (finishInflate == false) {
+ // this is a merge rInflate!
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(false);
+ }
}
}
}
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 2792100..acc7379 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -194,7 +194,9 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
Capability.RENDER,
Capability.LAYOUT_ONLY,
Capability.EMBEDDED_LAYOUT,
- Capability.VIEW_MANIPULATION);
+ Capability.VIEW_MANIPULATION,
+ Capability.PLAY_ANIMATION,
+ Capability.ANIMATED_VIEW_MANIPULATION);
BridgeAssetManager.initSystem();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index bf22c4d..765fd99 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -126,8 +126,19 @@ public class BridgeRenderSession extends RenderSession {
@Override
public Result animate(Object targetObject, String animationName,
boolean isFrameworkAnimation, IAnimationListener listener) {
- // Animation is only supported in API 11+
- return super.animate(targetObject, animationName, isFrameworkAnimation, listener);
+ try {
+ Bridge.prepareThread();
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mSession.animate(targetObject, animationName, isFrameworkAnimation,
+ listener);
+ }
+ } finally {
+ mSession.release();
+ Bridge.cleanupThread();
+ }
+
+ return mLastResult;
}
@Override
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 c4eee17..7d794bd 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
@@ -28,6 +28,7 @@ import com.android.resources.ResourceType;
import com.android.util.Pair;
import android.app.Activity;
+import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -44,6 +45,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
@@ -125,6 +127,9 @@ public final class BridgeContext extends Activity {
mRenderResources = renderResources;
+ mFragments.mCurState = Fragment.CREATED;
+ mFragments.mActivity = this;
+
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.targetSdkVersion = targetSdkVersion;
}
@@ -988,6 +993,13 @@ public final class BridgeContext extends Activity {
}
@Override
+ public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
+ CursorFactory arg2, DatabaseErrorHandler arg3) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
public Drawable peekWallpaper() {
// TODO Auto-generated method stub
return null;
@@ -1125,6 +1137,12 @@ public final class BridgeContext extends Activity {
}
@Override
+ public void startActivities(Intent[] arg0) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
public boolean isRestricted() {
return false;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index cb8d8dd..5740e8b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -122,10 +122,10 @@ public final class BridgeInflater extends LayoutInflater {
}
@Override
- public View createViewFromTag(String name, AttributeSet attrs) {
+ public View createViewFromTag(View parent, String name, AttributeSet attrs) {
View view = null;
try {
- view = super.createViewFromTag(name, attrs);
+ view = super.createViewFromTag(parent, name, attrs);
} catch (InflateException e) {
// try to load the class from using the custom view loader
try {
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 0efa102..a8da377 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
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.view.DragEvent;
import android.view.IWindow;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -81,6 +82,10 @@ public final class BridgeWindow implements IWindow {
// pass for now.
}
+ public void dispatchDragEvent(DragEvent event) {
+ // pass for now.
+ }
+
public void dispatchSystemUiVisibilityChanged(int visibility) {
// 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 7866bfa..8422d48 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
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.android;
+import android.content.ClipData;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -25,6 +26,7 @@ import android.os.RemoteException;
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.InputChannel;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.WindowManager.LayoutParams;
@@ -52,6 +54,10 @@ public final class BridgeWindowSession implements IWindowSession {
// pass for now.
}
+ public void finishKey(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
public boolean getInTouchMode() throws RemoteException {
// pass for now.
return false;
@@ -62,6 +68,16 @@ public final class BridgeWindowSession implements IWindowSession {
return false;
}
+ public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ return null;
+ }
+
+ public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ return null;
+ }
+
public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
throws RemoteException {
@@ -85,6 +101,38 @@ public final class BridgeWindowSession implements IWindowSession {
// pass for now.
}
+ public void setInsets(IWindow window, int touchable, Rect contentInsets,
+ Rect visibleInsets, Region touchableRegion) {
+ // pass for now.
+ }
+
+ public IBinder prepareDrag(IWindow window, int flags,
+ int thumbnailWidth, int thumbnailHeight, Surface outSurface)
+ throws RemoteException {
+ // pass for now
+ return null;
+ }
+
+ public boolean performDrag(IWindow window, IBinder dragToken,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data)
+ throws RemoteException {
+ // pass for now
+ return false;
+ }
+
+ public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
+ // pass for now
+ }
+
+ public void dragRecipientEntered(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
+ public void dragRecipientExited(IWindow window) throws RemoteException {
+ // pass for now
+ }
+
public void setWallpaperPosition(IBinder window, float x, float y,
float xStep, float yStep) {
// pass for now.
@@ -104,13 +152,18 @@ public final class BridgeWindowSession implements IWindowSession {
// pass for now.
}
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
}
- public void setInsets(IWindow arg0, int arg1, Rect arg2, Rect arg3) throws RemoteException {
+ public IBinder prepareDrag(IWindow arg0, boolean arg1, int arg2, int arg3, Surface arg4)
+ throws RemoteException {
// TODO Auto-generated method stub
-
+ return null;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
new file mode 100644
index 0000000..3af4e3a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class FakeActionBar extends CustomBar {
+
+ private TextView mTextView;
+
+ public FakeActionBar(Context context, Density density, String label, String icon)
+ throws XmlPullParserException {
+ super(context, density, "/bars/action_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ loadIcon(0, icon);
+ mTextView = setText(1, label);
+
+ setStyle("actionBarStyle");
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return mTextView;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
index 5507ef9..9fab51a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -38,7 +38,7 @@ public class PhoneSystemBar extends CustomBar {
// Cannot access the inside items through id because no R.id values have been
// created for them.
// We do know the order though.
- // 0 is the spacer.
+ // 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) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
new file mode 100644
index 0000000..5ca68fa
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 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.bars;
+
+import com.android.resources.Density;
+import com.android.resources.ResourceType;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LevelListDrawable;
+import android.widget.TextView;
+
+public class TabletSystemBar extends CustomBar {
+
+ public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
+ super(context, density, "/bars/tablet_system_bar.xml");
+
+ setBackgroundColor(0xFF000000);
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ loadIcon(0, "ic_sysbar_back_default.png", density);
+ loadIcon(1, "ic_sysbar_home_default.png", density);
+ loadIcon(2, "ic_sysbar_recent_default.png", density);
+ // 3 is the spacer
+ loadIcon(4, "stat_sys_wifi_signal_4_fully.png", density);
+ Drawable drawable = loadIcon(5, ResourceType.DRAWABLE, "stat_sys_battery_charge");
+ if (drawable instanceof LevelListDrawable) {
+ ((LevelListDrawable) drawable).setLevel(100);
+ }
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
new file mode 100644
index 0000000..4c18656
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 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;
+
+import com.android.ide.common.rendering.api.IAnimationListener;
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.Result.Status;
+import com.android.layoutlib.bridge.Bridge;
+
+import android.animation.ValueAnimator;
+import android.os.Handler;
+import android.os.Handler_Delegate;
+import android.os.Message;
+import android.os.Handler_Delegate.IHandlerCallback;
+
+import java.util.PriorityQueue;
+import java.util.Queue;
+
+/**
+ * Abstract animation thread.
+ * <p/>
+ * This does not actually start an animation, instead it fakes a looper that will play whatever
+ * animation is sending messages to its own {@link Handler}.
+ * <p/>
+ * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}.
+ * <p/>
+ * If {@link #preAnimation()} does not start an animation somehow then the thread doesn't do
+ * anything.
+ *
+ */
+public abstract class AnimationThread extends Thread {
+
+ private static class MessageBundle implements Comparable<MessageBundle> {
+ final Handler mTarget;
+ final Message mMessage;
+ final long mUptimeMillis;
+
+ MessageBundle(Handler target, Message message, long uptimeMillis) {
+ mTarget = target;
+ mMessage = message;
+ mUptimeMillis = uptimeMillis;
+ }
+
+ public int compareTo(MessageBundle bundle) {
+ if (mUptimeMillis < bundle.mUptimeMillis) {
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ private final RenderSessionImpl mSession;
+
+ private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>();
+ private final IAnimationListener mListener;
+
+ public AnimationThread(RenderSessionImpl scene, String threadName,
+ IAnimationListener listener) {
+ super(threadName);
+ mSession = scene;
+ mListener = listener;
+ }
+
+ public abstract Result preAnimation();
+ public abstract void postAnimation();
+
+ @Override
+ public void run() {
+ Bridge.prepareThread();
+ try {
+ Handler_Delegate.setCallback(new IHandlerCallback() {
+ public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
+ if (msg.what == ValueAnimator.ANIMATION_START ||
+ msg.what == ValueAnimator.ANIMATION_FRAME) {
+ mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
+ } else {
+ // just ignore.
+ }
+ }
+ });
+
+ // call out to the pre-animation work, which should start an animation or more.
+ Result result = preAnimation();
+ if (result.isSuccess() == false) {
+ mListener.done(result);
+ }
+
+ // loop the animation
+ RenderSession session = mSession.getSession();
+ do {
+ // check early.
+ if (mListener.isCanceled()) {
+ break;
+ }
+
+ // get the next message.
+ MessageBundle bundle = mQueue.poll();
+ if (bundle == null) {
+ break;
+ }
+
+ // sleep enough for this bundle to be on time
+ long currentTime = System.currentTimeMillis();
+ if (currentTime < bundle.mUptimeMillis) {
+ try {
+ sleep(bundle.mUptimeMillis - currentTime);
+ } catch (InterruptedException e) {
+ // FIXME log/do something/sleep again?
+ e.printStackTrace();
+ }
+ }
+
+ // check after sleeping.
+ if (mListener.isCanceled()) {
+ break;
+ }
+
+ // ready to do the work, acquire the scene.
+ result = mSession.acquire(250);
+ if (result.isSuccess() == false) {
+ mListener.done(result);
+ return;
+ }
+
+ // process the bundle. If the animation is not finished, this will enqueue
+ // the next message, so mQueue will have another one.
+ try {
+ // check after acquiring in case it took a while.
+ if (mListener.isCanceled()) {
+ break;
+ }
+
+ bundle.mTarget.handleMessage(bundle.mMessage);
+ if (mSession.render(false /*freshRender*/).isSuccess()) {
+ mListener.onNewFrame(session);
+ }
+ } finally {
+ mSession.release();
+ }
+ } while (mListener.isCanceled() == false && mQueue.size() > 0);
+
+ mListener.done(Status.SUCCESS.createResult());
+
+ } catch (Throwable throwable) {
+ // can't use Bridge.getLog() as the exception might be thrown outside
+ // of an acquire/release block.
+ mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable));
+
+ } finally {
+ postAnimation();
+ Handler_Delegate.setCallback(null);
+ Bridge.cleanupThread();
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 1cf64a8..21d6b1a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -166,6 +166,12 @@ public class GcSnapshot {
return mOriginalCopy;
}
+ void change() {
+ if (mBitmap != null) {
+ mBitmap.change();
+ }
+ }
+
/**
* Sets the clip for the graphics2D object associated with the layer.
* This should be used over the normal Graphics2D setClip method.
@@ -605,6 +611,7 @@ public class GcSnapshot {
try {
drawable.draw(configuredGraphics2D, paint);
+ layer.change();
} finally {
// dispose Graphics2D object
configuredGraphics2D.dispose();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
new file mode 100644
index 0000000..35e5987
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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;
+
+import com.android.ide.common.rendering.api.IAnimationListener;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.Result.Status;
+
+import android.animation.Animator;
+
+public class PlayAnimationThread extends AnimationThread {
+
+ private final Animator mAnimator;
+
+ public PlayAnimationThread(Animator animator, RenderSessionImpl scene, String animName,
+ IAnimationListener listener) {
+ super(scene, animName, listener);
+ mAnimator = animator;
+ }
+
+ @Override
+ public Result preAnimation() {
+ // start the animation. This will send a message to the handler right away, so
+ // the queue is filled when this method returns.
+ mAnimator.start();
+
+ return Status.SUCCESS.createResult();
+ }
+
+ @Override
+ public void postAnimation() {
+ // nothing to be done.
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 10a4368..953d8cf 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -87,6 +87,7 @@ public class RenderDrawable extends RenderAction<DrawableParams> {
info.mHasWindowFocus = true;
info.mWindowVisibility = View.VISIBLE;
info.mInTouchMode = false; // this is so that we can display selections.
+ info.mHardwareAccelerated = false;
content.dispatchAttachedToWindow(info, 0);
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 cfc047f..2fd58e4 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
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.impl;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_ANIM_NOT_FOUND;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
@@ -42,7 +43,9 @@ import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeWindow;
import com.android.layoutlib.bridge.android.BridgeWindowSession;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.bars.FakeActionBar;
import com.android.layoutlib.bridge.bars.PhoneSystemBar;
+import com.android.layoutlib.bridge.bars.TabletSystemBar;
import com.android.layoutlib.bridge.bars.TitleBar;
import com.android.resources.ResourceType;
import com.android.resources.ScreenSize;
@@ -50,6 +53,11 @@ import com.android.util.Pair;
import org.xmlpull.v1.XmlPullParserException;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
+import android.app.Fragment_Delegate;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
@@ -64,6 +72,7 @@ import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import android.widget.QuickContactBadge;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TabHost.TabSpec;
@@ -103,7 +112,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
private boolean mWindowIsFloating;
private int mStatusBarSize;
+ private int mSystemBarSize;
private int mTitleBarSize;
+ private int mActionBarSize;
// information being returned through the API
@@ -163,11 +174,13 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
findBackground(resources);
findStatusBar(resources, metrics);
- findTitleBar(resources, metrics);
+ findActionBar(resources, metrics);
+ findSystemBar(resources, metrics);
// build the inflater and parser.
mInflater = new BridgeInflater(context, params.getProjectCallback());
context.setBridgeInflater(mInflater);
+ mInflater.setFactory2(context);
mBlockParser = new BridgeXmlBlockParser(
params.getLayoutDescription(), context, false /* platformResourceFlag */);
@@ -201,16 +214,18 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* we're creating the following layout
*
+-------------------------------------------------+
- | System bar |
+ | System bar (only in phone UI) |
+-------------------------------------------------+
| (Layout with background drawable) |
| +---------------------------------------------+ |
- | | Title (optional) | |
+ | | Title/Action bar (optional) | |
| +---------------------------------------------+ |
| | Content, vertical extending | |
| | | |
| +---------------------------------------------+ |
+-------------------------------------------------+
+ | System bar (only in tablet UI) |
+ +-------------------------------------------------+
*/
@@ -242,8 +257,20 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
topLayout.addView(backgroundLayout);
- // if the theme says no title, then the size will be 0
- if (mTitleBarSize > 0) {
+ // if the theme says no title/action bar, then the size will be 0
+ if (mActionBarSize > 0) {
+ try {
+ FakeActionBar actionBar = new FakeActionBar(context,
+ params.getDensity(),
+ params.getAppLabel(), params.getAppIcon());
+ actionBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mActionBarSize));
+ backgroundLayout.addView(actionBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ } else if (mTitleBarSize > 0) {
try {
TitleBar titleBar = new TitleBar(context,
params.getDensity(), params.getAppLabel());
@@ -256,6 +283,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
+
// content frame
mContentRoot = new FrameLayout(context);
layoutParams = new LinearLayout.LayoutParams(
@@ -263,17 +291,38 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
layoutParams.weight = 1;
mContentRoot.setLayoutParams(layoutParams);
backgroundLayout.addView(mContentRoot);
+
+ if (mSystemBarSize > 0) {
+ // system bar
+ try {
+ TabletSystemBar systemBar = new TabletSystemBar(context,
+ params.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mSystemBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
}
+ // Sets the project callback (custom view loader) to the fragment delegate so that
+ // it can instantiate the custom Fragment.
+ Fragment_Delegate.setProjectCallback(params.getProjectCallback());
+
View view = mInflater.inflate(mBlockParser, mContentRoot);
+ Fragment_Delegate.setProjectCallback(null);
+
// set the AttachInfo on the root view.
AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
new Handler(), null);
info.mHasWindowFocus = true;
info.mWindowVisibility = View.VISIBLE;
info.mInTouchMode = false; // this is so that we can display selections.
+ info.mHardwareAccelerated = false;
mViewRoot.dispatchAttachedToWindow(info, 0);
// post-inflate process. For now this supports TabHost/TabWidget
@@ -445,6 +494,64 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
/**
+ * Animate an object
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see RenderSession#animate(Object, String, boolean, IAnimationListener)
+ */
+ public Result animate(Object targetObject, String animationName,
+ boolean isFrameworkAnimation, IAnimationListener listener) {
+ checkLock();
+
+ BridgeContext context = getContext();
+
+ // find the animation file.
+ ResourceValue animationResource = null;
+ int animationId = 0;
+ if (isFrameworkAnimation) {
+ animationResource = context.getRenderResources().getFrameworkResource(
+ ResourceType.ANIMATOR, animationName);
+ if (animationResource != null) {
+ animationId = Bridge.getResourceId(ResourceType.ANIMATOR, animationName);
+ }
+ } else {
+ animationResource = context.getRenderResources().getProjectResource(
+ ResourceType.ANIMATOR, animationName);
+ if (animationResource != null) {
+ animationId = context.getProjectCallback().getResourceId(
+ ResourceType.ANIMATOR, animationName);
+ }
+ }
+
+ if (animationResource != null) {
+ try {
+ Animator anim = AnimatorInflater.loadAnimator(context, animationId);
+ if (anim != null) {
+ anim.setTarget(targetObject);
+
+ new PlayAnimationThread(anim, this, animationName, listener).start();
+
+ return SUCCESS.createResult();
+ }
+ } catch (Exception e) {
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ return ERROR_UNKNOWN.createResult(t.getMessage(), t);
+ }
+ }
+
+ return ERROR_ANIM_NOT_FOUND.createResult();
+ }
+
+ /**
* Insert a new child into an existing parent.
* <p>
* {@link #acquire(long)} must have been called before this.
@@ -455,7 +562,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
* @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
*/
public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
- final int index, final IAnimationListener listener) {
+ final int index, IAnimationListener listener) {
checkLock();
BridgeContext context = getContext();
@@ -473,33 +580,17 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
invalidateRenderingSize();
if (listener != null) {
- // there is no support for animating views in this API level, so we fake the animation
- // through a no animation thread.
- new Thread("not animated insertChild") {
- @Override
- public void run() {
- Result result = addView(parentView, child, index);
- if (result.isSuccess() == false) {
- listener.done(result);
- }
+ new AnimationThread(this, "insertChild", listener) {
- // ready to do the work, acquire the scene.
- result = acquire(250);
- if (result.isSuccess() == false) {
- listener.done(result);
- return;
- }
-
- try {
- result = render(false /*freshRender*/);
- if (result.isSuccess()) {
- listener.onNewFrame(RenderSessionImpl.this.getSession());
- }
- } finally {
- release();
- }
+ @Override
+ public Result preAnimation() {
+ parentView.setLayoutTransition(new LayoutTransition());
+ return addView(parentView, child, index);
+ }
- listener.done(result);
+ @Override
+ public void postAnimation() {
+ parentView.setLayoutTransition(null);
}
}.start();
@@ -571,36 +662,72 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
if (listener != null) {
final LayoutParams params = layoutParams;
- // there is no support for animating views in this API level, so we fake the animation
- // through a no animation thread.
- new Thread("not animated moveChild") {
- @Override
- public void run() {
- Result result = moveView(previousParent, newParentView, childView, index,
- params);
- if (result.isSuccess() == false) {
- listener.done(result);
- }
+ // there is no support for animating views across layouts, so in case the new and old
+ // parent views are different we fake the animation through a no animation thread.
+ if (previousParent != newParentView) {
+ new Thread("not animated moveChild") {
+ @Override
+ public void run() {
+ Result result = moveView(previousParent, newParentView, childView, index,
+ params);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ }
+
+ // ready to do the work, acquire the scene.
+ result = acquire(250);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ return;
+ }
+
+ try {
+ result = render(false /*freshRender*/);
+ if (result.isSuccess()) {
+ listener.onNewFrame(RenderSessionImpl.this.getSession());
+ }
+ } finally {
+ release();
+ }
- // ready to do the work, acquire the scene.
- result = acquire(250);
- if (result.isSuccess() == false) {
listener.done(result);
- return;
}
+ }.start();
+ } else {
+ new AnimationThread(this, "moveChild", listener) {
- try {
- result = render(false /*freshRender*/);
- if (result.isSuccess()) {
- listener.onNewFrame(RenderSessionImpl.this.getSession());
- }
- } finally {
- release();
+ @Override
+ public Result preAnimation() {
+ // set up the transition for the parent.
+ LayoutTransition transition = new LayoutTransition();
+ previousParent.setLayoutTransition(transition);
+
+ // tweak the animation durations and start delays (to match the duration of
+ // animation playing just before).
+ // Note: Cannot user Animation.setDuration() directly. Have to set it
+ // on the LayoutTransition.
+ transition.setDuration(LayoutTransition.DISAPPEARING, 100);
+ // CHANGE_DISAPPEARING plays after DISAPPEARING
+ transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 100);
+
+ transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 100);
+
+ transition.setDuration(LayoutTransition.CHANGE_APPEARING, 100);
+ // CHANGE_APPEARING plays after CHANGE_APPEARING
+ transition.setStartDelay(LayoutTransition.APPEARING, 100);
+
+ transition.setDuration(LayoutTransition.APPEARING, 100);
+
+ return moveView(previousParent, newParentView, childView, index, params);
}
- listener.done(result);
- }
- }.start();
+ @Override
+ public void postAnimation() {
+ previousParent.setLayoutTransition(null);
+ newParentView.setLayoutTransition(null);
+ }
+ }.start();
+ }
// always return success since the real status will come through the listener.
return SUCCESS.createResult(layoutParams);
@@ -636,17 +763,66 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
final View movedView, final int index, final LayoutParams params) {
try {
- // standard code with no animation. pretty simple.
- previousParent.removeView(movedView);
+ // check if there is a transition on the previousParent.
+ LayoutTransition previousTransition = previousParent.getLayoutTransition();
+ if (previousTransition != null) {
+ // in this case there is an animation. This means we have to wait for the child's
+ // parent reference to be null'ed out so that we can add it to the new parent.
+ // It is technically removed right before the DISAPPEARING animation is done (if
+ // the animation of this type is not null, otherwise it's after which is impossible
+ // to handle).
+ // Because there is no move animation, if the new parent is the same as the old
+ // parent, we need to wait until the CHANGE_DISAPPEARING animation is done before
+ // adding the child or the child will appear in its new location before the
+ // other children have made room for it.
+
+ // add a listener to the transition to be notified of the actual removal.
+ previousTransition.addTransitionListener(new TransitionListener() {
+ private int mChangeDisappearingCount = 0;
+
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
+ mChangeDisappearingCount++;
+ }
+ }
+
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
+ mChangeDisappearingCount--;
+ }
+
+ if (transitionType == LayoutTransition.CHANGE_DISAPPEARING &&
+ mChangeDisappearingCount == 0) {
+ // add it to the parentView in the correct location
+ if (params != null) {
+ newParent.addView(movedView, index, params);
+ } else {
+ newParent.addView(movedView, index);
+ }
+ }
+ }
+ });
+
+ // remove the view from the current parent.
+ previousParent.removeView(movedView);
- // add it to the parentView in the correct location
- if (params != null) {
- newParent.addView(movedView, index, params);
+ // and return since adding the view to the new parent is done in the listener.
+ return SUCCESS.createResult();
} else {
- newParent.addView(movedView, index);
- }
+ // standard code with no animation. pretty simple.
+ previousParent.removeView(movedView);
- return SUCCESS.createResult();
+ // add it to the parentView in the correct location
+ if (params != null) {
+ newParent.addView(movedView, index, params);
+ } else {
+ newParent.addView(movedView, index);
+ }
+
+ return SUCCESS.createResult();
+ }
} catch (UnsupportedOperationException e) {
// looks like this is a view class that doesn't support children manipulation!
return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
@@ -663,7 +839,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
*
* @see RenderSession#removeChild(Object, IAnimationListener)
*/
- public Result removeChild(final View childView, final IAnimationListener listener) {
+ public Result removeChild(final View childView, IAnimationListener listener) {
checkLock();
invalidateRenderingSize();
@@ -671,33 +847,17 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
final ViewGroup parent = (ViewGroup) childView.getParent();
if (listener != null) {
- // there is no support for animating views in this API level, so we fake the animation
- // through a no animation thread.
- new Thread("not animated moveChild") {
- @Override
- public void run() {
- Result result = removeView(parent, childView);
- if (result.isSuccess() == false) {
- listener.done(result);
- }
+ new AnimationThread(this, "moveChild", listener) {
- // ready to do the work, acquire the scene.
- result = acquire(250);
- if (result.isSuccess() == false) {
- listener.done(result);
- return;
- }
-
- try {
- result = render(false /*freshRender*/);
- if (result.isSuccess()) {
- listener.onNewFrame(RenderSessionImpl.this.getSession());
- }
- } finally {
- release();
- }
+ @Override
+ public Result preAnimation() {
+ parent.setLayoutTransition(new LayoutTransition());
+ return removeView(parent, childView);
+ }
- listener.done(result);
+ @Override
+ public void postAnimation() {
+ parent.setLayoutTransition(null);
}
}.start();
@@ -742,43 +902,50 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
}
- private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
- boolean windowFullscreen = getBooleanThemeValue(resources,
- "windowFullscreen", false /*defaultValue*/);
-
- if (windowFullscreen == false && mWindowIsFloating == false) {
- // default value
- mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
-
- // get the real value
- ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
- "status_bar_height");
+ private boolean isTabletUi() {
+ return getParams().getConfigScreenSize() == ScreenSize.XLARGE;
+ }
- if (value != null) {
- TypedValue typedValue = ResourceHelper.getValue(value.getValue());
- if (typedValue != null) {
- // compute the pixel value based on the display metrics
- mStatusBarSize = (int)typedValue.getDimension(metrics);
+ private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
+ if (isTabletUi() == false) {
+ boolean windowFullscreen = getBooleanThemeValue(resources,
+ "windowFullscreen", false /*defaultValue*/);
+
+ if (windowFullscreen == false && mWindowIsFloating == false) {
+ // default value
+ mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
+
+ // get the real value
+ ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
+ "status_bar_height");
+
+ if (value != null) {
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mStatusBarSize = (int)typedValue.getDimension(metrics);
+ }
}
}
}
}
- private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
+ private void findActionBar(RenderResources resources, DisplayMetrics metrics) {
if (mWindowIsFloating) {
return;
}
- boolean windowNoTitle = getBooleanThemeValue(resources,
- "windowNoTitle", false /*defaultValue*/);
+ boolean windowActionBar = getBooleanThemeValue(resources,
+ "windowActionBar", true /*defaultValue*/);
- if (windowNoTitle == false) {
+ // if there's a value and it's false (default is true)
+ if (windowActionBar) {
// default size of the window title bar
- mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
+ mActionBarSize = DEFAULT_TITLE_BAR_HEIGHT;
// get value from the theme.
- ResourceValue value = resources.findItemInTheme("windowTitleSize");
+ ResourceValue value = resources.findItemInTheme("actionBarSize");
// resolve it
value = resources.resolveResValue(value);
@@ -788,7 +955,53 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
TypedValue typedValue = ResourceHelper.getValue(value.getValue());
if (typedValue != null) {
// compute the pixel value based on the display metrics
- mTitleBarSize = (int)typedValue.getDimension(metrics);
+ mActionBarSize = (int)typedValue.getDimension(metrics);
+ }
+ }
+ } else {
+ // action bar overrides title bar so only look for this one if action bar is hidden
+ boolean windowNoTitle = getBooleanThemeValue(resources,
+ "windowNoTitle", false /*defaultValue*/);
+
+ if (windowNoTitle == false) {
+
+ // default size of the window title bar
+ mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
+
+ // get value from the theme.
+ ResourceValue value = resources.findItemInTheme("windowTitleSize");
+
+ // resolve it
+ value = resources.resolveResValue(value);
+
+ if (value != null) {
+ // get the numerical value, if available
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mTitleBarSize = (int)typedValue.getDimension(metrics);
+ }
+ }
+ }
+
+ }
+ }
+
+ private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
+ if (isTabletUi() && mWindowIsFloating == false) {
+
+ // default value
+ mSystemBarSize = 48; // ??
+
+ // get the real value
+ ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
+ "status_bar_height");
+
+ if (value != null) {
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mSystemBarSize = (int)typedValue.getDimension(metrics);
}
}
}
@@ -823,6 +1036,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
throws PostInflateException {
if (view instanceof TabHost) {
setupTabHost((TabHost)view, projectCallback);
+ } else if (view instanceof QuickContactBadge) {
+ QuickContactBadge badge = (QuickContactBadge) view;
+ badge.setImageToDefault();
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup)view;
final int count = group.getChildCount();
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
new file mode 100644
index 0000000..e6dc646
--- /dev/null
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2011 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 libcore.icu;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.util.Locale;
+
+/**
+ * Delegate implementing the native methods of libcore.icu.ICU
+ *
+ * Through the layoutlib_create tool, the original native methods of ICU have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class ICU_Delegate {
+
+ // --- Java delegates
+
+ @LayoutlibDelegate
+ /*package*/ static String toLowerCase(String s, String localeName) {
+ return s.toLowerCase();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String toUpperCase(String s, String localeName) {
+ return s.toUpperCase();
+ }
+
+ // --- Native methods accessing ICU's database.
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableBreakIteratorLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableCalendarLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableCollatorLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableDateFormatLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getAvailableNumberFormatLocalesNative() {
+ return new String[0];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getCurrencyCodeNative(String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getCurrencyFractionDigitsNative(String currencyCode) {
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getCurrencySymbolNative(String locale, String currencyCode) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getDisplayCountryNative(String countryCode, String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getDisplayLanguageNative(String languageCode, String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getDisplayVariantNative(String variantCode, String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getISO3CountryNative(String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getISO3LanguageNative(String locale) {
+ return "";
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getISOLanguagesNative() {
+ return Locale.getISOLanguages();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String[] getISOCountriesNative() {
+ return Locale.getISOCountries();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean initLocaleDataImpl(String locale, LocaleData result) {
+
+ // Used by Calendar.
+ result.firstDayOfWeek = Integer.valueOf(1);
+ result.minimalDaysInFirstWeek = Integer.valueOf(1);
+
+ // Used by DateFormatSymbols.
+ result.amPm = new String[] { "AM", "PM" };
+ result.eras = new String[] { "BC", "AD" };
+
+ result.longMonthNames = new String[] { "January", "February", "March", "April", "May",
+ "June", "July", "August", "September", "October", "November", "December" };
+ result.shortMonthNames = new String[] { "Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ result.longStandAloneMonthNames = result.longMonthNames;
+ result.shortStandAloneMonthNames = result.shortMonthNames;
+
+ result.longWeekdayNames = new String[] {
+ "Monday" ,"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
+ result.shortWeekdayNames = new String[] {
+ "Mon" ,"Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ result.longStandAloneWeekdayNames = result.longWeekdayNames;
+ result.shortStandAloneWeekdayNames = result.shortWeekdayNames;
+
+ result.fullTimeFormat = "";
+ result.longTimeFormat = "";
+ result.mediumTimeFormat = "";
+ result.shortTimeFormat = "";
+
+ result.fullDateFormat = "";
+ result.longDateFormat = "";
+ result.mediumDateFormat = "";
+ result.shortDateFormat = "";
+
+ // Used by DecimalFormatSymbols.
+ result.zeroDigit = '0';
+ result.digit = '0';
+ result.decimalSeparator = '.';
+ result.groupingSeparator = ',';
+ result.patternSeparator = ' ';
+ result.percent = '%';
+ result.perMill = '\u2030';
+ result.monetarySeparator = ' ';
+ result.minusSign = '-';
+ result.exponentSeparator = "e";
+ result.infinity = "\u221E";
+ result.NaN = "NaN";
+ // Also used by Currency.
+ result.currencySymbol = "$";
+ result.internationalCurrencySymbol = "USD";
+
+ // Used by DecimalFormat and NumberFormat.
+ result.numberPattern = "%f";
+ result.integerPattern = "%d";
+ result.currencyPattern = "%s";
+ result.percentPattern = "%f";
+
+ return true;
+ }
+}
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 4b62e43..eff6bbc 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
@@ -94,12 +94,13 @@ public final class CreateInfo implements ICreateInfo {
* The list of methods to rewrite as delegates.
*/
private final static String[] DELEGATE_METHODS = new String[] {
+ "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
"android.content.res.Resources$Theme#obtainStyledAttributes",
"android.content.res.Resources$Theme#resolveAttribute",
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",
"android.os.Build#getString",
- "android.view.LayoutInflater#parseInclude",
+ "android.view.LayoutInflater#rInflate",
"android.view.View#isInEditMode",
"com.android.internal.util.XmlUtils#convertValueToInt",
// TODO: comment out once DelegateClass is working
@@ -109,6 +110,7 @@ public final class CreateInfo implements ICreateInfo {
* The list of classes on which to delegate all native methods.
*/
private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+ "android.animation.PropertyValuesHolder",
"android.graphics.AvoidXfermode",
"android.graphics.Bitmap",
"android.graphics.BitmapFactory",
@@ -148,6 +150,7 @@ public final class CreateInfo implements ICreateInfo {
"android.graphics.Xfermode",
"android.os.SystemClock",
"android.util.FloatMath",
+ "libcore.icu.ICU",
};
/**
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 0fce7ef..ce48069 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
@@ -68,6 +68,7 @@ public class Main {
AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,
new String[] { // derived from
"android.view.View",
+ "android.app.Fragment"
},
new String[] { // include classes
"android.*", // for android.R
diff --git a/tools/orientationplot/README.txt b/tools/orientationplot/README.txt
new file mode 100644
index 0000000..0143510
--- /dev/null
+++ b/tools/orientationplot/README.txt
@@ -0,0 +1,87 @@
+This directory contains a simple python script for visualizing
+the behavior of the WindowOrientationListener.
+
+
+PREREQUISITES
+-------------
+
+1. Python 2.6
+2. numpy
+3. matplotlib
+
+
+USAGE
+-----
+
+The tool works by scaping the debug log output from WindowOrientationListener
+for interesting data and then plotting it.
+
+1. Enable the Window Orientation Listener debugging data log using the
+ Development Settings in the Dev Tools application (Development.apk).
+
+2. Plug in the device. Ensure that it is the only device plugged in
+ since this script is of very little brain and will get confused otherwise.
+
+3. Run "orientationplot.py".
+
+4. When finished, remember to disable the debug log output since it is quite verbose!
+
+
+WHAT IT ALL MEANS
+-----------------
+
+The tool displays several time series graphs that plot the output of the
+WindowOrientationListener. Here you can see the raw accelerometer data,
+filtered accelerometer data, measured tilt and orientation angle, confidence
+intervals for the proposed orientation and accelerometer latency.
+
+Things to look for:
+
+1. Ensure the filtering is not too aggressive. If the filter cut-off frequency is
+ less than about 1Hz, then the filtered accelorometer data becomes too smooth
+ and the latency for orientation detection goes up. One way to observe this
+ is by holding the device vertically in one orientation then sharply turning
+ it 90 degrees to a different orientation. Compared the rapid changes in the
+ raw accelerometer data with the smoothed out filtered data. If the filtering
+ is too aggressive, the filter response may lag by hundreds of milliseconds.
+
+2. Ensure that there is an appropriate gap between adjacent orientation angles
+ for hysteresis. Try holding the device in one orientation and slowly turning
+ it 90 degrees. Note that the confidence intervals will all drop to 0 at some
+ point in between the two orientations; that is the gap. The gap should be
+ observed between all adjacent pairs of orientations when turning the device
+ in either direction.
+
+ Next try holding the device in one orientation and rapidly turning it end
+ over end to a midpoint about 45 degrees between two opposing orientations.
+ There should be no gap observed initially. The algorithm should pick one
+ of the orientations and settle into it (since it is obviously quite
+ different from the original orientation of the device). However, once it
+ settles, the confidence values should start trending to 0 again because
+ the measured orientation angle is now within the gap between the new
+ orientation and the adjacent orientation.
+
+ In other words, the hysteresis gap applies only when the measured orientation
+ angle (say, 45 degrees) is between the current orientation's ideal angle
+ (say, 0 degrees) and an adjacent orientation's ideal angle (say, 90 degrees).
+
+3. Accelerometer jitter. The accelerometer latency graph displays the interval
+ between sensor events as reported by the SensorEvent.timestamp field. It
+ should be a fairly constant 60ms. If the latency jumps around wildly or
+ greatly exceeds 60ms then there is a problem with the accelerometer or the
+ sensor manager.
+
+4. The orientation angle is not measured when the tilt is too close to 90 or -90
+ degrees (refer to MAX_TILT constant). Consequently, you should expect there
+ to be no data. Likewise, all dependent calculations are suppressed in this case
+ so there will be no orientation proposal either.
+
+5. Each orientation has its own bound on allowable tilt angles. It's a good idea to
+ verify that these limits are being enforced by gradually varying the tilt of
+ the device until it is inside/outside the limit for each orientation.
+
+6. Orientation changes should be significantly harder when the device is held
+ overhead. People reading on tablets in bed often have their head turned
+ a little to the side, or they hold the device loosely so its orientation
+ can be a bit unusual. The tilt is a good indicator of whether the device is
+ overhead.
diff --git a/tools/orientationplot/orientationplot.py b/tools/orientationplot/orientationplot.py
new file mode 100755
index 0000000..07449d4
--- /dev/null
+++ b/tools/orientationplot/orientationplot.py
@@ -0,0 +1,451 @@
+#!/usr/bin/env python2.6
+#
+# Copyright (C) 2011 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.
+#
+
+#
+# Plots debug log output from WindowOrientationListener.
+# See README.txt for details.
+#
+
+import numpy as np
+import matplotlib.pyplot as plot
+import subprocess
+import re
+import fcntl
+import os
+import errno
+import bisect
+from datetime import datetime, timedelta
+
+# Parameters.
+timespan = 15 # seconds total span shown
+scrolljump = 5 # seconds jump when scrolling
+timeticks = 1 # seconds between each time tick
+
+# Non-blocking stream wrapper.
+class NonBlockingStream:
+ def __init__(self, stream):
+ fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
+ self.stream = stream
+ self.buffer = ''
+ self.pos = 0
+
+ def readline(self):
+ while True:
+ index = self.buffer.find('\n', self.pos)
+ if index != -1:
+ result = self.buffer[self.pos:index]
+ self.pos = index + 1
+ return result
+
+ self.buffer = self.buffer[self.pos:]
+ self.pos = 0
+ try:
+ chunk = os.read(self.stream.fileno(), 4096)
+ except OSError, e:
+ if e.errno == errno.EAGAIN:
+ return None
+ raise e
+ if len(chunk) == 0:
+ if len(self.buffer) == 0:
+ raise(EOFError)
+ else:
+ result = self.buffer
+ self.buffer = ''
+ self.pos = 0
+ return result
+ self.buffer += chunk
+
+# Plotter
+class Plotter:
+ def __init__(self, adbout):
+ self.adbout = adbout
+
+ self.fig = plot.figure(1)
+ self.fig.suptitle('Window Orientation Listener', fontsize=12)
+ self.fig.set_dpi(96)
+ self.fig.set_size_inches(16, 12, forward=True)
+
+ self.raw_acceleration_x = self._make_timeseries()
+ self.raw_acceleration_y = self._make_timeseries()
+ self.raw_acceleration_z = self._make_timeseries()
+ self.raw_acceleration_axes = self._add_timeseries_axes(
+ 1, 'Raw Acceleration', 'm/s^2', [-20, 20],
+ yticks=range(-15, 16, 5))
+ self.raw_acceleration_line_x = self._add_timeseries_line(
+ self.raw_acceleration_axes, 'x', 'red')
+ self.raw_acceleration_line_y = self._add_timeseries_line(
+ self.raw_acceleration_axes, 'y', 'green')
+ self.raw_acceleration_line_z = self._add_timeseries_line(
+ self.raw_acceleration_axes, 'z', 'blue')
+ self._add_timeseries_legend(self.raw_acceleration_axes)
+
+ shared_axis = self.raw_acceleration_axes
+
+ self.filtered_acceleration_x = self._make_timeseries()
+ self.filtered_acceleration_y = self._make_timeseries()
+ self.filtered_acceleration_z = self._make_timeseries()
+ self.magnitude = self._make_timeseries()
+ self.filtered_acceleration_axes = self._add_timeseries_axes(
+ 2, 'Filtered Acceleration', 'm/s^2', [-20, 20],
+ sharex=shared_axis,
+ yticks=range(-15, 16, 5))
+ self.filtered_acceleration_line_x = self._add_timeseries_line(
+ self.filtered_acceleration_axes, 'x', 'red')
+ self.filtered_acceleration_line_y = self._add_timeseries_line(
+ self.filtered_acceleration_axes, 'y', 'green')
+ self.filtered_acceleration_line_z = self._add_timeseries_line(
+ self.filtered_acceleration_axes, 'z', 'blue')
+ self.magnitude_line = self._add_timeseries_line(
+ self.filtered_acceleration_axes, 'magnitude', 'orange', linewidth=2)
+ self._add_timeseries_legend(self.filtered_acceleration_axes)
+
+ self.tilt_angle = self._make_timeseries()
+ self.tilt_angle_axes = self._add_timeseries_axes(
+ 3, 'Tilt Angle', 'degrees', [-105, 105],
+ sharex=shared_axis,
+ yticks=range(-90, 91, 30))
+ self.tilt_angle_line = self._add_timeseries_line(
+ self.tilt_angle_axes, 'tilt', 'black')
+ self._add_timeseries_legend(self.tilt_angle_axes)
+
+ self.orientation_angle = self._make_timeseries()
+ self.orientation_angle_axes = self._add_timeseries_axes(
+ 4, 'Orientation Angle', 'degrees', [-25, 375],
+ sharex=shared_axis,
+ yticks=range(0, 361, 45))
+ self.orientation_angle_line = self._add_timeseries_line(
+ self.orientation_angle_axes, 'orientation', 'black')
+ self._add_timeseries_legend(self.orientation_angle_axes)
+
+ self.actual_orientation = self._make_timeseries()
+ self.proposed_orientation = self._make_timeseries()
+ self.orientation_axes = self._add_timeseries_axes(
+ 5, 'Actual / Proposed Orientation and Confidence', 'rotation', [-1, 4],
+ sharex=shared_axis,
+ yticks=range(0, 4))
+ self.actual_orientation_line = self._add_timeseries_line(
+ self.orientation_axes, 'actual', 'black', linewidth=2)
+ self.proposed_orientation_line = self._add_timeseries_line(
+ self.orientation_axes, 'proposed', 'purple', linewidth=3)
+ self._add_timeseries_legend(self.orientation_axes)
+
+ self.confidence = [[self._make_timeseries(), self._make_timeseries()] for i in range(0, 4)]
+ self.confidence_polys = []
+
+ self.combined_confidence = self._make_timeseries()
+ self.orientation_confidence = self._make_timeseries()
+ self.tilt_confidence = self._make_timeseries()
+ self.magnitude_confidence = self._make_timeseries()
+ self.confidence_axes = self._add_timeseries_axes(
+ 6, 'Proposed Orientation Confidence Factors', 'confidence', [-0.1, 1.1],
+ sharex=shared_axis,
+ yticks=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0])
+ self.combined_confidence_line = self._add_timeseries_line(
+ self.confidence_axes, 'combined', 'purple', linewidth=2)
+ self.orientation_confidence_line = self._add_timeseries_line(
+ self.confidence_axes, 'orientation', 'black')
+ self.tilt_confidence_line = self._add_timeseries_line(
+ self.confidence_axes, 'tilt', 'brown')
+ self.magnitude_confidence_line = self._add_timeseries_line(
+ self.confidence_axes, 'magnitude', 'orange')
+ self._add_timeseries_legend(self.confidence_axes)
+
+ self.sample_latency = self._make_timeseries()
+ self.sample_latency_axes = self._add_timeseries_axes(
+ 7, 'Accelerometer Sampling Latency', 'ms', [-10, 500],
+ sharex=shared_axis,
+ yticks=range(0, 500, 100))
+ self.sample_latency_line = self._add_timeseries_line(
+ self.sample_latency_axes, 'latency', 'black')
+ self._add_timeseries_legend(self.sample_latency_axes)
+
+ self.timer = self.fig.canvas.new_timer(interval=100)
+ self.timer.add_callback(lambda: self.update())
+ self.timer.start()
+
+ self.timebase = None
+ self._reset_parse_state()
+
+ # Initialize a time series.
+ def _make_timeseries(self):
+ return [[], []]
+
+ # Add a subplot to the figure for a time series.
+ def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
+ num_graphs = 7
+ height = 0.9 / num_graphs
+ top = 0.95 - height * index
+ axes = self.fig.add_axes([0.1, top, 0.8, height],
+ xscale='linear',
+ xlim=[0, timespan],
+ ylabel=ylabel,
+ yscale='linear',
+ ylim=ylim,
+ sharex=sharex)
+ axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
+ axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
+ axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
+ axes.set_xticks(range(0, timespan + 1, timeticks))
+ axes.set_yticks(yticks)
+ axes.grid(True)
+
+ for label in axes.get_xticklabels():
+ label.set_fontsize(9)
+ for label in axes.get_yticklabels():
+ label.set_fontsize(9)
+
+ return axes
+
+ # Add a line to the axes for a time series.
+ def _add_timeseries_line(self, axes, label, color, linewidth=1):
+ return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
+
+ # Add a legend to a time series.
+ def _add_timeseries_legend(self, axes):
+ axes.legend(
+ loc='upper left',
+ bbox_to_anchor=(1.01, 1),
+ borderpad=0.1,
+ borderaxespad=0.1,
+ prop={'size': 10})
+
+ # Resets the parse state.
+ def _reset_parse_state(self):
+ self.parse_raw_acceleration_x = None
+ self.parse_raw_acceleration_y = None
+ self.parse_raw_acceleration_z = None
+ self.parse_filtered_acceleration_x = None
+ self.parse_filtered_acceleration_y = None
+ self.parse_filtered_acceleration_z = None
+ self.parse_magnitude = None
+ self.parse_tilt_angle = None
+ self.parse_orientation_angle = None
+ self.parse_proposed_orientation = None
+ self.parse_combined_confidence = None
+ self.parse_orientation_confidence = None
+ self.parse_tilt_confidence = None
+ self.parse_magnitude_confidence = None
+ self.parse_actual_orientation = None
+ self.parse_confidence = None
+ self.parse_sample_latency = None
+
+ # Update samples.
+ def update(self):
+ timeindex = 0
+ while True:
+ try:
+ line = self.adbout.readline()
+ except EOFError:
+ plot.close()
+ return
+ if line is None:
+ break
+ print line
+
+ try:
+ timestamp = self._parse_timestamp(line)
+ except ValueError, e:
+ continue
+ if self.timebase is None:
+ self.timebase = timestamp
+ delta = timestamp - self.timebase
+ timeindex = delta.seconds + delta.microseconds * 0.000001
+
+ if line.find('Raw acceleration vector:') != -1:
+ self.parse_raw_acceleration_x = self._get_following_number(line, 'x=')
+ self.parse_raw_acceleration_y = self._get_following_number(line, 'y=')
+ self.parse_raw_acceleration_z = self._get_following_number(line, 'z=')
+
+ if line.find('Filtered acceleration vector:') != -1:
+ self.parse_filtered_acceleration_x = self._get_following_number(line, 'x=')
+ self.parse_filtered_acceleration_y = self._get_following_number(line, 'y=')
+ self.parse_filtered_acceleration_z = self._get_following_number(line, 'z=')
+
+ if line.find('magnitude=') != -1:
+ self.parse_magnitude = self._get_following_number(line, 'magnitude=')
+
+ if line.find('tiltAngle=') != -1:
+ self.parse_tilt_angle = self._get_following_number(line, 'tiltAngle=')
+
+ if line.find('orientationAngle=') != -1:
+ self.parse_orientation_angle = self._get_following_number(line, 'orientationAngle=')
+
+ if line.find('Proposal:') != -1:
+ self.parse_proposed_orientation = self._get_following_number(line, 'proposedOrientation=')
+ self.parse_combined_confidence = self._get_following_number(line, 'combinedConfidence=')
+ self.parse_orientation_confidence = self._get_following_number(line, 'orientationConfidence=')
+ self.parse_tilt_confidence = self._get_following_number(line, 'tiltConfidence=')
+ self.parse_magnitude_confidence = self._get_following_number(line, 'magnitudeConfidence=')
+
+ if line.find('Result:') != -1:
+ self.parse_actual_orientation = self._get_following_number(line, 'rotation=')
+ self.parse_confidence = self._get_following_array_of_numbers(line, 'confidence=')
+ self.parse_sample_latency = self._get_following_number(line, 'timeDeltaMS=')
+
+ for i in range(0, 4):
+ if self.parse_confidence is not None:
+ self._append(self.confidence[i][0], timeindex, i)
+ self._append(self.confidence[i][1], timeindex, i + self.parse_confidence[i])
+ else:
+ self._append(self.confidence[i][0], timeindex, None)
+ self._append(self.confidence[i][1], timeindex, None)
+
+ self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x)
+ self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y)
+ self._append(self.raw_acceleration_z, timeindex, self.parse_raw_acceleration_z)
+ self._append(self.filtered_acceleration_x, timeindex, self.parse_filtered_acceleration_x)
+ self._append(self.filtered_acceleration_y, timeindex, self.parse_filtered_acceleration_y)
+ self._append(self.filtered_acceleration_z, timeindex, self.parse_filtered_acceleration_z)
+ self._append(self.magnitude, timeindex, self.parse_magnitude)
+ self._append(self.tilt_angle, timeindex, self.parse_tilt_angle)
+ self._append(self.orientation_angle, timeindex, self.parse_orientation_angle)
+ self._append(self.actual_orientation, timeindex, self.parse_actual_orientation)
+ self._append(self.proposed_orientation, timeindex, self.parse_proposed_orientation)
+ self._append(self.combined_confidence, timeindex, self.parse_combined_confidence)
+ self._append(self.orientation_confidence, timeindex, self.parse_orientation_confidence)
+ self._append(self.tilt_confidence, timeindex, self.parse_tilt_confidence)
+ self._append(self.magnitude_confidence, timeindex, self.parse_magnitude_confidence)
+ self._append(self.sample_latency, timeindex, self.parse_sample_latency)
+ self._reset_parse_state()
+
+ # Scroll the plots.
+ if timeindex > timespan:
+ bottom = int(timeindex) - timespan + scrolljump
+ self.timebase += timedelta(seconds=bottom)
+ self._scroll(self.raw_acceleration_x, bottom)
+ self._scroll(self.raw_acceleration_y, bottom)
+ self._scroll(self.raw_acceleration_z, bottom)
+ self._scroll(self.filtered_acceleration_x, bottom)
+ self._scroll(self.filtered_acceleration_y, bottom)
+ self._scroll(self.filtered_acceleration_z, bottom)
+ self._scroll(self.magnitude, bottom)
+ self._scroll(self.tilt_angle, bottom)
+ self._scroll(self.orientation_angle, bottom)
+ self._scroll(self.actual_orientation, bottom)
+ self._scroll(self.proposed_orientation, bottom)
+ self._scroll(self.combined_confidence, bottom)
+ self._scroll(self.orientation_confidence, bottom)
+ self._scroll(self.tilt_confidence, bottom)
+ self._scroll(self.magnitude_confidence, bottom)
+ self._scroll(self.sample_latency, bottom)
+ for i in range(0, 4):
+ self._scroll(self.confidence[i][0], bottom)
+ self._scroll(self.confidence[i][1], bottom)
+
+ # Redraw the plots.
+ self.raw_acceleration_line_x.set_data(self.raw_acceleration_x)
+ self.raw_acceleration_line_y.set_data(self.raw_acceleration_y)
+ self.raw_acceleration_line_z.set_data(self.raw_acceleration_z)
+ self.filtered_acceleration_line_x.set_data(self.filtered_acceleration_x)
+ self.filtered_acceleration_line_y.set_data(self.filtered_acceleration_y)
+ self.filtered_acceleration_line_z.set_data(self.filtered_acceleration_z)
+ self.magnitude_line.set_data(self.magnitude)
+ self.tilt_angle_line.set_data(self.tilt_angle)
+ self.orientation_angle_line.set_data(self.orientation_angle)
+ self.actual_orientation_line.set_data(self.actual_orientation)
+ self.proposed_orientation_line.set_data(self.proposed_orientation)
+ self.combined_confidence_line.set_data(self.combined_confidence)
+ self.orientation_confidence_line.set_data(self.orientation_confidence)
+ self.tilt_confidence_line.set_data(self.tilt_confidence)
+ self.magnitude_confidence_line.set_data(self.magnitude_confidence)
+ self.sample_latency_line.set_data(self.sample_latency)
+
+ for poly in self.confidence_polys:
+ poly.remove()
+ self.confidence_polys = []
+ for i in range(0, 4):
+ self.confidence_polys.append(self.orientation_axes.fill_between(self.confidence[i][0][0],
+ self.confidence[i][0][1], self.confidence[i][1][1],
+ facecolor='goldenrod', edgecolor='goldenrod'))
+
+ self.fig.canvas.draw_idle()
+
+ # Scroll a time series.
+ def _scroll(self, timeseries, bottom):
+ bottom_index = bisect.bisect_left(timeseries[0], bottom)
+ del timeseries[0][:bottom_index]
+ del timeseries[1][:bottom_index]
+ for i, timeindex in enumerate(timeseries[0]):
+ timeseries[0][i] = timeindex - bottom
+
+ # Extract a word following the specified prefix.
+ def _get_following_word(self, line, prefix):
+ prefix_index = line.find(prefix)
+ if prefix_index == -1:
+ return None
+ start_index = prefix_index + len(prefix)
+ delim_index = line.find(',', start_index)
+ if delim_index == -1:
+ return line[start_index:]
+ else:
+ return line[start_index:delim_index]
+
+ # Extract a number following the specified prefix.
+ def _get_following_number(self, line, prefix):
+ word = self._get_following_word(line, prefix)
+ if word is None:
+ return None
+ return float(word)
+
+ # Extract an array of numbers following the specified prefix.
+ def _get_following_array_of_numbers(self, line, prefix):
+ prefix_index = line.find(prefix + '[')
+ if prefix_index == -1:
+ return None
+ start_index = prefix_index + len(prefix) + 1
+ delim_index = line.find(']', start_index)
+ if delim_index == -1:
+ return None
+
+ result = []
+ while start_index < delim_index:
+ comma_index = line.find(', ', start_index, delim_index)
+ if comma_index == -1:
+ result.append(float(line[start_index:delim_index]))
+ break;
+ result.append(float(line[start_index:comma_index]))
+ start_index = comma_index + 2
+ return result
+
+ # Add a value to a time series.
+ def _append(self, timeseries, timeindex, number):
+ timeseries[0].append(timeindex)
+ timeseries[1].append(number)
+
+ # Parse the logcat timestamp.
+ # Timestamp has the form '01-21 20:42:42.930'
+ def _parse_timestamp(self, line):
+ return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
+
+# Notice
+print "Window Orientation Listener plotting tool"
+print "-----------------------------------------\n"
+print "Please turn on the Window Orientation Listener logging in Development Settings."
+
+# Start adb.
+print "Starting adb logcat.\n"
+
+adb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'WindowOrientationListener:V'],
+ stdout=subprocess.PIPE)
+adbout = NonBlockingStream(adb.stdout)
+
+# Prepare plotter.
+plotter = Plotter(adbout)
+plotter.update()
+
+# Main loop.
+plot.show()
diff --git a/tools/preload/Record.java b/tools/preload/Record.java
index 9d45a26..2f2ffaf 100644
--- a/tools/preload/Record.java
+++ b/tools/preload/Record.java
@@ -30,6 +30,8 @@ class Record {
"com.google.android.apps.maps\\u003Adriveabout",
"com.google.android.apps.maps:LocationFriendService",
"com.google.android.apps.maps\\u003ALocationFriendService",
+ "com.google.android.apps.maps:NetworkLocationService",
+ "com.google.android.apps.maps\\u003ANetworkLocationService",
};
enum Type {
@@ -69,7 +71,7 @@ class Record {
/** Record time (ns). */
final long time;
-
+
/** Source file line# */
int sourceLineNumber;
@@ -91,7 +93,7 @@ class Record {
for (int i = 0; i < REPLACE_CLASSES.length; i+= 2) {
line = line.replace(REPLACE_CLASSES[i], REPLACE_CLASSES[i+1]);
}
-
+
line = line.substring(1);
String[] parts = line.split(":");
@@ -106,12 +108,12 @@ class Record {
time = Long.parseLong(parts[6]);
}
-
+
/**
* Decode any escaping that may have been written to the log line.
- *
+ *
* Supports unicode-style escaping: \\uXXXX = character in hex
- *
+ *
* @param rawField the field as it was written into the log
* @result the same field with any escaped characters replaced
*/
@@ -122,11 +124,11 @@ class Record {
String before = result.substring(0, offset);
String escaped = result.substring(offset+2, offset+6);
String after = result.substring(offset+6);
-
+
result = String.format("%s%c%s", before, Integer.parseInt(escaped, 16), after);
- // find another but don't recurse
- offset = result.indexOf("\\u", offset + 1);
+ // find another but don't recurse
+ offset = result.indexOf("\\u", offset + 1);
}
return result;
}
@@ -135,13 +137,13 @@ class Record {
* Converts a VM-style name to a language-style name.
*/
String vmTypeToLanguage(String typeName) {
- // if the typename is (null), just return it as-is. This is probably in dexopt and
+ // if the typename is (null), just return it as-is. This is probably in dexopt and
// will be discarded anyway. NOTE: This corresponds to the case in dalvik/vm/oo/Class.c
// where dvmLinkClass() returns false and we clean up and exit.
if ("(null)".equals(typeName)) {
return typeName;
}
-
+
if (!typeName.startsWith("L") || !typeName.endsWith(";") ) {
throw new AssertionError("Bad name: " + typeName + " in line " + sourceLineNumber);
}
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
new file mode 100644
index 0000000..90979e1
--- /dev/null
+++ b/tools/validatekeymaps/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright 2010 The Android Open Source Project
+#
+# Keymap validation tool.
+#
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS),)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ Main.cpp
+
+LOCAL_CFLAGS := -Wall -Werror
+
+#LOCAL_C_INCLUDES +=
+
+LOCAL_STATIC_LIBRARIES := \
+ libui \
+ libutils \
+ libcutils
+
+ifeq ($(HOST_OS),linux)
+LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_MODULE := validatekeymaps
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # TARGET_BUILD_APPS
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
new file mode 100644
index 0000000..097b109
--- /dev/null
+++ b/tools/validatekeymaps/Main.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <ui/KeyCharacterMap.h>
+#include <ui/KeyLayoutMap.h>
+#include <ui/VirtualKeyMap.h>
+#include <utils/String8.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace android;
+
+static const char* gProgName = "validatekeymaps";
+
+enum FileType {
+ FILETYPE_UNKNOWN,
+ FILETYPE_KEYLAYOUT,
+ FILETYPE_KEYCHARACTERMAP,
+ FILETYPE_VIRTUALKEYDEFINITION,
+};
+
+
+static void usage() {
+ fprintf(stderr, "Keymap Validation Tool\n\n");
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr,
+ " %s [*.kl] [*.kcm] [virtualkeys.*] [...]\n"
+ " Validates the specified key layouts, key character maps \n"
+ " or virtual key definitions.\n\n",
+ gProgName);
+}
+
+static FileType getFileType(const char* filename) {
+ const char *extension = strrchr(filename, '.');
+ if (extension) {
+ if (strcmp(extension, ".kl") == 0) {
+ return FILETYPE_KEYLAYOUT;
+ }
+ if (strcmp(extension, ".kcm") == 0) {
+ return FILETYPE_KEYCHARACTERMAP;
+ }
+ }
+
+ if (strstr(filename, "virtualkeys.")) {
+ return FILETYPE_VIRTUALKEYDEFINITION;
+ }
+
+ return FILETYPE_UNKNOWN;
+}
+
+static bool validateFile(const char* filename) {
+ fprintf(stdout, "Validating file '%s'...\n", filename);
+
+ FileType fileType = getFileType(filename);
+ switch (fileType) {
+ case FILETYPE_UNKNOWN:
+ fprintf(stderr, "Supported file types: *.kl, *.kcm, virtualkeys.*\n\n");
+ return false;
+
+ case FILETYPE_KEYLAYOUT: {
+ KeyLayoutMap* map;
+ status_t status = KeyLayoutMap::load(String8(filename), &map);
+ if (status) {
+ fprintf(stderr, "Error %d parsing key layout file.\n\n", status);
+ return false;
+ }
+ break;
+ }
+
+ case FILETYPE_KEYCHARACTERMAP: {
+ KeyCharacterMap* map;
+ status_t status = KeyCharacterMap::load(String8(filename), &map);
+ if (status) {
+ fprintf(stderr, "Error %d parsing key character map file.\n\n", status);
+ return false;
+ }
+ break;
+ }
+
+ case FILETYPE_VIRTUALKEYDEFINITION: {
+ VirtualKeyMap* map;
+ status_t status = VirtualKeyMap::load(String8(filename), &map);
+ if (status) {
+ fprintf(stderr, "Error %d parsing virtual key definition file.\n\n", status);
+ return false;
+ }
+ break;
+ }
+ }
+
+ fputs("No errors.\n\n", stdout);
+ return true;
+}
+
+int main(int argc, const char** argv) {
+ if (argc < 2) {
+ usage();
+ return 1;
+ }
+
+ int result = 0;
+ for (int i = 1; i < argc; i++) {
+ if (!validateFile(argv[i])) {
+ result = 1;
+ }
+ }
+
+ if (result) {
+ fputs("Failed!\n", stderr);
+ } else {
+ fputs("Success.\n", stdout);
+ }
+ return result;
+}