donut snapshot
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 6bc1ee6..67af116 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -187,6 +187,13 @@
         return 0;
     }
 
+    // screen layout
+    if (getScreenLayoutName(part.string(), &config)) {
+        *axis = AXIS_SCREENLAYOUT;
+        *value = config.screenLayout;
+        return 0;
+    }
+
     // version
     if (getVersionName(part.string(), &config)) {
         *axis = AXIS_VERSION;
@@ -202,7 +209,7 @@
 {
     Vector<String8> parts;
 
-    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, vers;
+    String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers;
 
     const char *p = dir;
     const char *q;
@@ -378,6 +385,18 @@
         //printf("not screen size: %s\n", part.string());
     }
 
+    if (getScreenLayoutName(part.string())) {
+        layout = part;
+
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index];
+    } else {
+        //printf("not screen layout: %s\n", part.string());
+    }
+
     if (getVersionName(part.string())) {
         vers = part;
 
@@ -404,6 +423,7 @@
     this->keyboard = key;
     this->navigation = nav;
     this->screenSize = size;
+    this->screenLayout = layout;
     this->version = vers;
 
     // what is this anyway?
@@ -435,6 +455,8 @@
     s += ",";
     s += screenSize;
     s += ",";
+    s += screenLayout;
+    s += ",";
     s += version;
     return s;
 }
@@ -483,6 +505,10 @@
         s += "-";
         s += screenSize;
     }
+    if (this->screenLayout != "") {
+        s += "-";
+        s += screenLayout;
+    }
     if (this->version != "") {
         s += "-";
         s += version;
@@ -786,6 +812,26 @@
     return true;
 }
 
+bool AaptGroupEntry::getScreenLayoutName(const char* name,
+                                     ResTable_config* out)
+{
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_ANY;
+        return true;
+    } else if (strcmp(name, "smallscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_SMALL;
+        return true;
+    } else if (strcmp(name, "normalscreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL;
+        return true;
+    } else if (strcmp(name, "largescreen") == 0) {
+        if (out) out->screenLayout = out->SCREENLAYOUT_LARGE;
+        return true;
+    }
+
+    return false;
+}
+
 bool AaptGroupEntry::getVersionName(const char* name,
                                     ResTable_config* out)
 {
@@ -828,6 +874,7 @@
     if (v == 0) v = keyboard.compare(o.keyboard);
     if (v == 0) v = navigation.compare(o.navigation);
     if (v == 0) v = screenSize.compare(o.screenSize);
+    if (v == 0) v = screenLayout.compare(o.screenLayout);
     if (v == 0) v = version.compare(o.version);
     return v;
 }
@@ -846,6 +893,7 @@
     getKeyboardName(keyboard.string(), &params);
     getNavigationName(navigation.string(), &params);
     getScreenSizeName(screenSize.string(), &params);
+    getScreenLayoutName(screenLayout.string(), &params);
     getVersionName(version.string(), &params);
     return params;
 }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 01c8140..3b96412 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -37,6 +37,7 @@
     AXIS_KEYBOARD,
     AXIS_NAVIGATION,
     AXIS_SCREENSIZE,
+    AXIS_SCREENLAYOUT,
     AXIS_VERSION
 };
 
@@ -62,6 +63,7 @@
     String8 keyboard;
     String8 navigation;
     String8 screenSize;
+    String8 screenLayout;
     String8 version;
 
     bool initFromDirName(const char* dir, String8* resType);
@@ -78,6 +80,7 @@
     static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
     static bool getNavigationName(const char* name, ResTable_config* out = NULL);
     static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
+    static bool getScreenLayoutName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
     int compare(const AaptGroupEntry& o) const;
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2d8471b..a6fedf3 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -34,10 +34,13 @@
           mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
           mUpdate(false), mExtending(false),
           mRequireLocalization(false), mPseudolocalize(false),
+          mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL),
           mAssetSourceDir(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL),
+          mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
+          mVersionCode(NULL), mVersionName(NULL),
           mArgc(0), mArgv(NULL)
         {}
     ~Bundle(void) {}
@@ -70,6 +73,8 @@
     void setRequireLocalization(bool val) { mRequireLocalization = val; }
     bool getPseudolocalize(void) const { return mPseudolocalize; }
     void setPseudolocalize(bool val) { mPseudolocalize = val; }
+    bool getValues(void) const { return mValues; }
+    void setValues(bool val) { mValues = val; }
     int getCompressionMethod(void) const { return mCompressionMethod; }
     void setCompressionMethod(int val) { mCompressionMethod = val; }
     const char* getOutputAPKFile() const { return mOutputAPKFile; }
@@ -99,6 +104,17 @@
     const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; }
     void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); }
 
+    const char*  getMinSdkVersion() const { return mMinSdkVersion; }
+    void setMinSdkVersion(const char*  val) { mMinSdkVersion = val; }
+    const char*  getTargetSdkVersion() const { return mTargetSdkVersion; }
+    void setTargetSdkVersion(const char*  val) { mTargetSdkVersion = val; }
+    const char*  getMaxSdkVersion() const { return mMaxSdkVersion; }
+    void setMaxSdkVersion(const char*  val) { mMaxSdkVersion = val; }
+    const char*  getVersionCode() const { return mVersionCode; }
+    void setVersionCode(const char*  val) { mVersionCode = val; }
+    const char* getVersionName() const { return mVersionName; }
+    void setVersionName(const char* val) { mVersionName = val; }
+    
     /*
      * Set and get the file specification.
      *
@@ -138,6 +154,7 @@
     bool        mExtending;
     bool        mRequireLocalization;
     bool        mPseudolocalize;
+    bool        mValues;
     int         mCompressionMethod;
     const char* mOutputAPKFile;
     const char* mAssetSourceDir;
@@ -151,6 +168,12 @@
     android::Vector<const char*> mNoCompressExtensions;
     android::Vector<const char*> mResourceSourceDirs;
     
+    const char* mMinSdkVersion;
+    const char* mTargetSdkVersion;
+    const char* mMaxSdkVersion;
+    const char* mVersionCode;
+    const char* mVersionName;
+    
     /* file specification */
     int         mArgc;
     char* const* mArgv;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 6f3461d..e04491d 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -196,7 +196,7 @@
             printf("\nNo resource table found.\n");
         } else {
             printf("\nResource table:\n");
-            res.print();
+            res.print(false);
         }
 
         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -268,17 +268,19 @@
     return str ? String8(str, len) : String8();
 }
 
-static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
+static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
+        String8* outError, int32_t defValue = -1)
 {
     ssize_t idx = indexOfAttribute(tree, attrRes);
     if (idx < 0) {
-        return -1;
+        return defValue;
     }
     Res_value value;
     if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
-        if (value.dataType != Res_value::TYPE_INT_DEC) {
+        if (value.dataType < Res_value::TYPE_FIRST_INT
+                || value.dataType > Res_value::TYPE_LAST_INT) {
             if (outError != NULL) *outError = "attribute is not an integer value";
-            return -1;
+            return defValue;
         }
     }
     return value.data;
@@ -318,7 +320,18 @@
     VERSION_NAME_ATTR = 0x0101021c,
     LABEL_ATTR = 0x01010001,
     ICON_ATTR = 0x01010002,
-    MIN_SDK_VERSION_ATTR = 0x0101020c
+    MIN_SDK_VERSION_ATTR = 0x0101020c,
+    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
+    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
+    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
+    REQ_NAVIGATION_ATTR = 0x0101022a,
+    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
+    TARGET_SDK_VERSION_ATTR = 0x01010270,
+    TEST_ONLY_ATTR = 0x01010272,
+    DENSITY_ATTR = 0x0101026c,
+    SMALL_SCREEN_ATTR = 0x01010284,
+    NORMAL_SCREEN_ATTR = 0x01010285,
+    LARGE_SCREEN_ATTR = 0x01010286,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -357,7 +370,8 @@
     const char* filename = bundle->getFileSpecEntry(1);
 
     AssetManager assets;
-    if (!assets.addAssetPath(String8(filename), NULL)) {
+    void* assetsCookie;
+    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
         fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
         return 1;
     }
@@ -369,7 +383,7 @@
     }
 
     if (strcmp("resources", option) == 0) {
-        res.print();
+        res.print(bundle->getValues());
 
     } else if (strcmp("xmltree", option) == 0) {
         if (bundle->getFileSpecCount() < 3) {
@@ -488,6 +502,10 @@
             bool isLauncherActivity = false;
             bool withinApplication = false;
             bool withinReceiver = false;
+            int targetSdk = 0;
+            int smallScreen = 1;
+            int normalScreen = 1;
+            int largeScreen = 1;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -543,15 +561,90 @@
                             goto bail;
                         }
                         printf("icon='%s'\n", icon.string());
-                    } else if (tag == "uses-sdk") {
-                        int32_t sdkVersion = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
                         if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", error.string());
+                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
                             goto bail;
                         }
-                        if (sdkVersion != -1) {
-                            printf("sdkVersion:'%d'\n", sdkVersion);
+                        if (testOnly != 0) {
+                            printf("testOnly='%d'\n", testOnly);
                         }
+                    } else if (tag == "uses-sdk") {
+                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+                        if (error != "") {
+                            error = "";
+                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
+                            if (name == "Donut") targetSdk = 4;
+                            printf("sdkVersion:'%s'\n", name.string());
+                        } else if (code != -1) {
+                            targetSdk = code;
+                            printf("sdkVersion:'%d'\n", code);
+                        }
+                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
+                        if (error != "") {
+                            error = "";
+                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
+                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
+                            printf("targetSdkVersion:'%s'\n", name.string());
+                        } else if (code != -1) {
+                            if (targetSdk < code) {
+                                targetSdk = code;
+                            }
+                            printf("targetSdkVersion:'%d'\n", code);
+                        }
+                    } else if (tag == "uses-configuration") {
+                        int32_t reqTouchScreen = getIntegerAttribute(tree,
+                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
+                        int32_t reqKeyboardType = getIntegerAttribute(tree,
+                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
+                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
+                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
+                        int32_t reqNavigation = getIntegerAttribute(tree,
+                                REQ_NAVIGATION_ATTR, NULL, 0);
+                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
+                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
+                        printf("uses-configuation:");
+                        if (reqTouchScreen != 0) {
+                            printf(" reqTouchScreen='%d'", reqTouchScreen);
+                        }
+                        if (reqKeyboardType != 0) {
+                            printf(" reqKeyboardType='%d'", reqKeyboardType);
+                        }
+                        if (reqHardKeyboard != 0) {
+                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
+                        }
+                        if (reqNavigation != 0) {
+                            printf(" reqNavigation='%d'", reqNavigation);
+                        }
+                        if (reqFiveWayNav != 0) {
+                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
+                        }
+                        printf("\n");
+                    } else if (tag == "supports-density") {
+                        int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
+                                    error.string());
+                            goto bail;
+                        }
+                        printf("supports-density:'%d'\n", dens);
+                    } else if (tag == "supports-screens") {
+                        smallScreen = getIntegerAttribute(tree,
+                                SMALL_SCREEN_ATTR, NULL, 1);
+                        normalScreen = getIntegerAttribute(tree,
+                                NORMAL_SCREEN_ATTR, NULL, 1);
+                        largeScreen = getIntegerAttribute(tree,
+                                LARGE_SCREEN_ATTR, NULL, 1);
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;
@@ -592,18 +685,18 @@
                         }
                     }
                 } else if (depth == 5) {
-                        if (withinActivity) {
-                            if (tag == "action") {
-                                //printf("LOG: action tag\n");
-                                String8 action = getAttribute(tree, NAME_ATTR, &error);
-                                if (error != "") {
-                                    fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
-                                    goto bail;
-                                }
-                                if (action == "android.intent.action.MAIN") {
-                                    isMainActivity = true;
-                                    //printf("LOG: isMainActivity==true\n");
-                                }
+                    if (withinActivity) {
+                        if (tag == "action") {
+                            //printf("LOG: action tag\n");
+                            String8 action = getAttribute(tree, NAME_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+                                goto bail;
+                            }
+                            if (action == "android.intent.action.MAIN") {
+                                isMainActivity = true;
+                                //printf("LOG: isMainActivity==true\n");
+                            }
                         } else if (tag == "category") {
                             String8 category = getAttribute(tree, NAME_ATTR, &error);
                             if (error != "") {
@@ -659,11 +752,31 @@
                            activityIcon.string());
                 }
             }
+            
+            // Determine default values for any unspecified screen sizes,
+            // based on the target SDK of the package.  As of 4 (donut)
+            // the screen size support was introduced, so all default to
+            // enabled.
+            if (smallScreen > 0) {
+                smallScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            if (normalScreen > 0) {
+                normalScreen = -1;
+            }
+            if (largeScreen > 0) {
+                largeScreen = targetSdk >= 4 ? -1 : 0;
+            }
+            printf("supports-screens:");
+            if (smallScreen != 0) printf(" 'small'");
+            if (normalScreen != 0) printf(" 'normal'");
+            if (largeScreen != 0) printf(" 'large'");
+            printf("\n");
+            
             printf("locales:");
             Vector<String8> locales;
             res.getLocales(&locales);
-            const size_t N = locales.size();
-            for (size_t i=0; i<N; i++) {
+            const size_t NL = locales.size();
+            for (size_t i=0; i<NL; i++) {
                 const char* localeStr =  locales[i].string();
                 if (localeStr == NULL || strlen(localeStr) == 0) {
                     localeStr = "--_--";
@@ -671,6 +784,35 @@
                 printf(" '%s'", localeStr);
             }
             printf("\n");
+            
+            Vector<ResTable_config> configs;
+            res.getConfigurations(&configs);
+            SortedVector<int> densities;
+            const size_t NC = configs.size();
+            for (size_t i=0; i<NC; i++) {
+                int dens = configs[i].density;
+                if (dens == 0) dens = 160;
+                densities.add(dens);
+            }
+            
+            printf("densities:");
+            const size_t ND = densities.size();
+            for (size_t i=0; i<ND; i++) {
+                printf(" '%d'", densities[i]);
+            }
+            printf("\n");
+            
+            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
+            if (dir != NULL) {
+                if (dir->getFileCount() > 0) {
+                    printf("native-code:");
+                    for (size_t i=0; i<dir->getFileCount(); i++) {
+                        printf(" '%s'", dir->getFileName(i).string());
+                    }
+                    printf("\n");
+                }
+                delete dir;
+            }
         } else if (strcmp("configurations", option) == 0) {
             Vector<ResTable_config> configs;
             res.getConfigurations(&configs);
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 71b1a3c..12a0445 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -45,7 +45,7 @@
         " %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
         "   List contents of Zip-compatible archive.\n\n", gProgName);
     fprintf(stderr,
-        " %s d[ump] WHAT file.{apk} [asset [asset ...]]\n"
+        " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
         "   badging          Print the label and icon for the app declared in APK.\n"
         "   permissions      Print the permissions from the APK.\n"
         "   resources        Print the resource table from the APK.\n"
@@ -54,9 +54,10 @@
         "   xmlstrings       Print the strings of the given compiled xml assets.\n\n", gProgName);
     fprintf(stderr,
         " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
-        "        [-0 extension [-0 extension ...]] \\\n"
-        "        [-g tolerance] \\\n"
-        "        [-j jarfile] \\\n"
+        "        [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
+        "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
+        "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
+        "        [--app-version-name TEXT] \\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
         "        [-A asset-source-dir] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
@@ -115,7 +116,19 @@
         "       and the first match found (left to right) will take precedence."
         "   -0  specifies an additional extension for which such files will not\n"
         "       be stored compressed in the .apk.  An empty string means to not\n"
-        "       compress any files at all.\n");
+        "       compress any files at all.\n"
+        "   --min-sdk-version\n"
+        "       inserts android:minSdkVersion in to manifest.\n"
+        "   --target-sdk-version\n"
+        "       inserts android:targetSdkVersion in to manifest.\n"
+        "   --max-sdk-version\n"
+        "       inserts android:maxSdkVersion in to manifest.\n"
+        "   --values\n"
+        "       when used with \"dump resources\" also includes resource values.\n"
+        "   --version-code\n"
+        "       inserts android:versionCode in to manifest.\n"
+        "   --version-name\n"
+        "       inserts android:versionName in to manifest.\n");
 }
 
 /*
@@ -339,6 +352,61 @@
                     bundle.setCompressionMethod(ZipEntry::kCompressStored);
                 }
                 break;
+            case '-':
+                if (strcmp(cp, "-min-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMinSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-target-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setTargetSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-max-sdk-version") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setMaxSdkVersion(argv[0]);
+                } else if (strcmp(cp, "-version-code") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionCode(argv[0]);
+                } else if (strcmp(cp, "-version-name") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.setVersionName(argv[0]);
+                } else if (strcmp(cp, "-values") == 0) {
+                    bundle.setValues(true);
+                } else {
+                    fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
+                    wantUsage = true;
+                    goto bail;
+                }
+                cp += strlen(cp) - 1;
+                break;
             default:
                 fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
                 wantUsage = true;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index b2bd9ff..027e3ab 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -433,7 +433,7 @@
     }
 }
 
-static void applyFileOverlay(const sp<AaptAssets>& assets, 
+static bool applyFileOverlay(const sp<AaptAssets>& assets,
                              const sp<ResourceTypeSet>& baseSet,
                              const char *resType)
 {
@@ -441,7 +441,7 @@
     // Also add any found only in the overlay.
     sp<AaptAssets> overlay = assets->getOverlay();
     String8 resTypeString(resType);
-    
+
     // work through the linked list of overlays
     while (overlay.get()) {
         KeyedVector<String8, sp<ResourceTypeSet> >* overlayRes = overlay->getResources();
@@ -456,7 +456,7 @@
             size_t overlayCount = overlaySet->size();
             for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
                 size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex));
-                if (baseIndex != UNKNOWN_ERROR) {
+                if (baseIndex < UNKNOWN_ERROR) {
                     // look for same flavor.  For a given file (strings.xml, for example)
                     // there may be a locale specific or other flavors - we want to match
                     // the same flavor.
@@ -482,9 +482,10 @@
                     }
                 } else {
                     // this group doesn't exist (a file that's only in the overlay)
-                    // add it
-                    baseSet->add(overlaySet->keyAt(overlayIndex),
-                                 overlaySet->valueAt(overlayIndex));
+                    fprintf(stderr, "aapt: error: "
+                            "*** Resource file '%s' exists only in an overlay\n",
+                            overlaySet->keyAt(overlayIndex).string());
+                    return false;
                 }
             }
             // this overlay didn't have resources for this type
@@ -492,7 +493,59 @@
         // try next overlay
         overlay = overlay->getOverlay();
     }
-    return;
+    return true;
+}
+
+void addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+        const char* attr8, const char* value)
+{
+    if (value == NULL) {
+        return;
+    }
+    
+    const String16 ns(ns8);
+    const String16 attr(attr8);
+    
+    if (node->getAttribute(ns, attr) != NULL) {
+        fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n",
+                String8(attr).string(), String8(ns).string());
+        return;
+    }
+    
+    node->addAttribute(ns, attr, String16(value));
+}
+
+status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
+{
+    root = root->searchElement(String16(), String16("manifest"));
+    if (root == NULL) {
+        fprintf(stderr, "No <manifest> tag.\n");
+        return UNKNOWN_ERROR;
+    }
+    
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
+            bundle->getVersionCode());
+    addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
+            bundle->getVersionName());
+    
+    if (bundle->getMinSdkVersion() != NULL
+            || bundle->getTargetSdkVersion() != NULL
+            || bundle->getMaxSdkVersion() != NULL) {
+        sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk"));
+        if (vers == NULL) {
+            vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk"));
+            root->insertChildAt(vers, 0);
+        }
+        
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion",
+                bundle->getMinSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion",
+                bundle->getTargetSdkVersion());
+        addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion",
+                bundle->getMaxSdkVersion());
+    }
+    
+    return NO_ERROR;
 }
 
 #define ASSIGN_IT(n) \
@@ -566,13 +619,15 @@
         current = current->getOverlay();
     }
     // apply the overlay files to the base set
-    applyFileOverlay(assets, drawables, "drawable");
-    applyFileOverlay(assets, layouts, "layout");
-    applyFileOverlay(assets, anims, "anim");
-    applyFileOverlay(assets, xmls, "xml");
-    applyFileOverlay(assets, raws, "raw");
-    applyFileOverlay(assets, colors, "color");
-    applyFileOverlay(assets, menus, "menu");
+    if (!applyFileOverlay(assets, drawables, "drawable") ||
+            !applyFileOverlay(assets, layouts, "layout") ||
+            !applyFileOverlay(assets, anims, "anim") ||
+            !applyFileOverlay(assets, xmls, "xml") ||
+            !applyFileOverlay(assets, raws, "raw") ||
+            !applyFileOverlay(assets, colors, "color") ||
+            !applyFileOverlay(assets, menus, "menu")) {
+        return UNKNOWN_ERROR;
+    }
 
     bool hasErrors = false;
 
@@ -1013,7 +1068,15 @@
 
     // Generate final compiled manifest file.
     manifestFile->clearData();
-    err = compileXmlFile(assets, manifestFile, &table);
+    sp<XMLNode> manifestTree = XMLNode::parse(manifestFile);
+    if (manifestTree == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    err = massageManifest(bundle, manifestTree);
+    if (err < NO_ERROR) {
+        return err;
+    }
+    err = compileXmlFile(assets, manifestTree, manifestFile, &table);
     if (err < NO_ERROR) {
         return err;
     }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index ef11a83..b004664 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -23,6 +23,16 @@
     if (root == NULL) {
         return UNKNOWN_ERROR;
     }
+    
+    return compileXmlFile(assets, root, target, table, options);
+}
+
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& root,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options)
+{
     if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
         root->removeWhitespace(true, NULL);
     } else  if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -651,6 +661,7 @@
     const String16 string_array16("string-array");
     const String16 integer_array16("integer-array");
     const String16 public16("public");
+    const String16 public_padding16("public-padding");
     const String16 private_symbols16("private-symbols");
     const String16 skip16("skip");
     const String16 eat_comment16("eat-comment");
@@ -685,7 +696,7 @@
 
     bool hasErrors = false;
     
-    uint32_t nextPublicId = 0;
+    DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
 
     ResXMLTree::event_code_t code;
     do {
@@ -718,6 +729,7 @@
             String16 curType;
             int32_t curFormat = ResTable_map::TYPE_ANY;
             bool curIsBag = false;
+            bool curIsBagReplaceOnOverwrite = false;
             bool curIsStyled = false;
             bool curIsPseudolocalizable = false;
             bool localHasErrors = false;
@@ -774,15 +786,15 @@
                         hasErrors = localHasErrors = true;
                     } else {
                         ident = identValue.data;
-                        nextPublicId = ident+1;
+                        nextPublicId.replaceValueFor(type, ident+1);
                     }
-                } else if (nextPublicId == 0) {
+                } else if (nextPublicId.indexOfKey(type) < 0) {
                     srcPos.error("No 'id' attribute supplied <public>,"
                             " and no previous id defined in this file.\n");
                     hasErrors = localHasErrors = true;
                 } else if (!localHasErrors) {
-                    ident = nextPublicId;
-                    nextPublicId++;
+                    ident = nextPublicId.valueFor(type);
+                    nextPublicId.replaceValueFor(type, ident+1);
                 }
 
                 if (!localHasErrors) {
@@ -816,6 +828,116 @@
                 }
                 continue;
 
+            } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+            
+                String16 type;
+                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+                if (typeIdx < 0) {
+                    srcPos.error("A 'type' attribute is required for <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                type = String16(block.getAttributeStringValue(typeIdx, &len));
+
+                String16 name;
+                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+                if (nameIdx < 0) {
+                    srcPos.error("A 'name' attribute is required for <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+                uint32_t start = 0;
+                ssize_t startIdx = block.indexOfAttribute(NULL, "start");
+                if (startIdx >= 0) {
+                    const char16_t* startStr = block.getAttributeStringValue(startIdx, &len);
+                    Res_value startValue;
+                    if (!ResTable::stringToInt(startStr, len, &startValue)) {
+                        srcPos.error("Given 'start' attribute is not an integer: %s\n",
+                                String8(block.getAttributeStringValue(startIdx, &len)).string());
+                        hasErrors = localHasErrors = true;
+                    } else {
+                        start = startValue.data;
+                    }
+                } else if (nextPublicId.indexOfKey(type) < 0) {
+                    srcPos.error("No 'start' attribute supplied <public-padding>,"
+                            " and no previous id defined in this file.\n");
+                    hasErrors = localHasErrors = true;
+                } else if (!localHasErrors) {
+                    start = nextPublicId.valueFor(type);
+                }
+
+                uint32_t end = 0;
+                ssize_t endIdx = block.indexOfAttribute(NULL, "end");
+                if (endIdx >= 0) {
+                    const char16_t* endStr = block.getAttributeStringValue(endIdx, &len);
+                    Res_value endValue;
+                    if (!ResTable::stringToInt(endStr, len, &endValue)) {
+                        srcPos.error("Given 'end' attribute is not an integer: %s\n",
+                                String8(block.getAttributeStringValue(endIdx, &len)).string());
+                        hasErrors = localHasErrors = true;
+                    } else {
+                        end = endValue.data;
+                    }
+                } else {
+                    srcPos.error("No 'end' attribute supplied <public-padding>\n");
+                    hasErrors = localHasErrors = true;
+                }
+
+                if (end >= start) {
+                    nextPublicId.replaceValueFor(type, end+1);
+                } else {
+                    srcPos.error("Padding start '%ul' is after end '%ul'\n",
+                            start, end);
+                    hasErrors = localHasErrors = true;
+                }
+                
+                String16 comment(
+                    block.getComment(&len) ? block.getComment(&len) : nulStr);
+                for (uint32_t curIdent=start; curIdent<=end; curIdent++) {
+                    if (localHasErrors) {
+                        break;
+                    }
+                    String16 curName(name);
+                    char buf[64];
+                    sprintf(buf, "%d", (int)(end-curIdent+1));
+                    curName.append(String16(buf));
+                    
+                    err = outTable->addEntry(srcPos, myPackage, type, curName,
+                                             String16("padding"), NULL, &curParams, false,
+                                             ResTable_map::TYPE_STRING, overwrite);
+                    if (err < NO_ERROR) {
+                        hasErrors = localHasErrors = true;
+                        break;
+                    }
+                    err = outTable->addPublic(srcPos, myPackage, type,
+                            curName, curIdent);
+                    if (err < NO_ERROR) {
+                        hasErrors = localHasErrors = true;
+                        break;
+                    }
+                    sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
+                    if (symbols != NULL) {
+                        symbols = symbols->addNestedSymbol(String8(type), srcPos);
+                    }
+                    if (symbols != NULL) {
+                        symbols->makeSymbolPublic(String8(curName), srcPos);
+                        symbols->appendComment(String8(curName), comment, srcPos);
+                    } else {
+                        srcPos.error("Unable to create symbols!\n");
+                        hasErrors = localHasErrors = true;
+                    }
+                }
+
+                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+                    if (code == ResXMLTree::END_TAG) {
+                        if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+                            break;
+                        }
+                    }
+                }
+                continue;
+
             } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
                 String16 pkg;
                 ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
@@ -1050,6 +1172,7 @@
                 curTag = &array16;
                 curType = array16;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
                 ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
                 if (formatIdx >= 0) {
                     String16 formatStr = String16(block.getAttributeStringValue(
@@ -1068,12 +1191,14 @@
                 curType = array16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
                 curIsPseudolocalizable = true;
             } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
                 curTag = &integer_array16;
                 curType = array16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
                 curIsBag = true;
+                curIsBagReplaceOnOverwrite = true;
             } else {
                 SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                         "Found tag %s where item is expected\n",
@@ -1108,9 +1233,10 @@
                 }
 
                 if (!localHasErrors) {
-                    err = outTable->startBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
-                                             myPackage, curType, ident, parentIdent, &curParams, 
-                                             overwrite);
+                    err = outTable->startBag(SourcePos(in->getPrintableSource(),
+                            block.getLineNumber()), myPackage, curType, ident,
+                            parentIdent, &curParams,
+                            overwrite, curIsBagReplaceOnOverwrite);
                     if (err != NO_ERROR) {
                         hasErrors = localHasErrors = true;
                     }
@@ -1307,7 +1433,7 @@
             } else if (id != 0) {
                 if (id == 127) {
                     if (mHaveAppPackage) {
-                        fprintf(stderr, "Included resource have two application packages!\n");
+                        fprintf(stderr, "Included resources have two application packages!\n");
                         return UNKNOWN_ERROR;
                     }
                     mHaveAppPackage = true;
@@ -1390,8 +1516,9 @@
                String8(value).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params, doSetIndex);
+
+    sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite,
+                           params, doSetIndex);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -1408,6 +1535,7 @@
                                  const String16& name,
                                  const String16& bagParent,
                                  const ResTable_config* params,
+                                 bool overlay,
                                  bool replace, bool isId)
 {
     status_t result = NO_ERROR;
@@ -1428,8 +1556,12 @@
                sourcePos.file.striing(), sourcePos.line, String8(type).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params);
+    if (overlay && !hasBagOrEntry(package, type, name)) {
+        sourcePos.error("Can't add new bags in an overlay.  See '%s'\n",
+                        String8(name).string());
+        return UNKNOWN_ERROR;
+    }
+    sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -1450,7 +1582,7 @@
         return result;
     }
 
-    if (replace) { 
+    if (overlay && replace) { 
         return e->emptyBag(sourcePos);
     }
     return result;
@@ -1483,8 +1615,7 @@
                sourcePos.file.striing(), sourcePos.line, String8(type).string());
     }
 #endif
-    
-    sp<Entry> e = getEntry(package, type, name, sourcePos, params);
+    sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
     if (e == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -2767,7 +2898,7 @@
                         mItem.sourcePos.file.string(), mItem.sourcePos.line);
         return UNKNOWN_ERROR;
     }
-    
+
     mType = TYPE_ITEM;
     mItem = item;
     mItemFormat = format;
@@ -3087,11 +3218,17 @@
 sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
                                                        const SourcePos& sourcePos,
                                                        const ResTable_config* config,
-                                                       bool doSetIndex)
+                                                       bool doSetIndex,
+                                                       bool overlay)
 {
     int pos = -1;
     sp<ConfigList> c = mConfigs.valueFor(entry);
     if (c == NULL) {
+        if (overlay == true) {
+            sourcePos.error("Resource %s appears in overlay but not"
+                            " in the base package.\n", String8(entry).string());
+            return NULL;
+        }
         c = new ConfigList(entry, sourcePos);
         mConfigs.add(entry, c);
         pos = (int)mOrderedConfigs.size();
@@ -3390,6 +3527,7 @@
                                                  const String16& type,
                                                  const String16& name,
                                                  const SourcePos& sourcePos,
+                                                 bool overlay,
                                                  const ResTable_config* config,
                                                  bool doSetIndex)
 {
@@ -3397,7 +3535,7 @@
     if (t == NULL) {
         return NULL;
     }
-    return t->getEntry(name, sourcePos, config, doSetIndex);
+    return t->getEntry(name, sourcePos, config, doSetIndex, overlay);
 }
 
 sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 74ba326..ec4331a 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -15,6 +15,7 @@
 
 using namespace std;
 
+class XMLNode;
 class ResourceTable;
 
 enum {
@@ -34,6 +35,12 @@
                         ResourceTable* table,
                         int options = XML_COMPILE_STANDARD_RESOURCE);
 
+status_t compileXmlFile(const sp<AaptAssets>& assets,
+                        const sp<XMLNode>& xmlTree,
+                        const sp<AaptFile>& target,
+                        ResourceTable* table,
+                        int options = XML_COMPILE_STANDARD_RESOURCE);
+
 status_t compileResourceFile(Bundle* bundle,
                              const sp<AaptAssets>& assets,
                              const sp<AaptFile>& in,
@@ -89,6 +96,7 @@
                     const String16& name,
                     const String16& bagParent,
                     const ResTable_config* params = NULL,
+                    bool overlay = false,
                     bool replace = false,
                     bool isId = false);
     
@@ -410,7 +418,8 @@
         sp<Entry> getEntry(const String16& entry,
                            const SourcePos& pos,
                            const ResTable_config* config = NULL,
-                           bool doSetIndex = false);
+                           bool doSetIndex = false,
+                           bool overlay = false);
 
         const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
 
@@ -494,6 +503,7 @@
                        const String16& type,
                        const String16& name,
                        const SourcePos& pos,
+                       bool overlay,
                        const ResTable_config* config = NULL,
                        bool doSetIndex = false);
     sp<const Entry> getEntry(uint32_t resID,
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index d476567..2a85bc7 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -524,12 +524,30 @@
     return mChildren;
 }
 
+const String8& XMLNode::getFilename() const
+{
+    return mFilename;
+}
+    
 const Vector<XMLNode::attribute_entry>&
     XMLNode::getAttributes() const
 {
     return mAttributes;
 }
 
+const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns,
+        const String16& name) const
+{
+    for (size_t i=0; i<mAttributes.size(); i++) {
+        const attribute_entry& ae(mAttributes.itemAt(i));
+        if (ae.ns == ns && ae.name == name) {
+            return &ae;
+        }
+    }
+    
+    return NULL;
+}
+
 const String16& XMLNode::getCData() const
 {
     return mChars;
@@ -550,6 +568,38 @@
     return mEndLineNumber;
 }
 
+sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName)
+{
+    if (getType() == XMLNode::TYPE_ELEMENT
+            && mNamespaceUri == tagNamespace
+            && mElementName == tagName) {
+        return this;
+    }
+    
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName);
+        if (found != NULL) {
+            return found;
+        }
+    }
+    
+    return NULL;
+}
+
+sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName)
+{
+    for (size_t i=0; i<mChildren.size(); i++) {
+        sp<XMLNode> child = mChildren.itemAt(i);
+        if (child->getType() == XMLNode::TYPE_ELEMENT
+                && child->mNamespaceUri == tagNamespace
+                && child->mElementName == tagName) {
+            return child;
+        }
+    }
+    
+    return NULL;
+}
+
 status_t XMLNode::addChild(const sp<XMLNode>& child)
 {
     if (getType() == TYPE_CDATA) {
@@ -561,6 +611,17 @@
     return NO_ERROR;
 }
 
+status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index)
+{
+    if (getType() == TYPE_CDATA) {
+        SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
+        return UNKNOWN_ERROR;
+    }
+    //printf("Adding child %p to parent %p\n", child.get(), this);
+    mChildren.insertAt(child, index);
+    return NO_ERROR;
+}
+
 status_t XMLNode::addAttribute(const String16& ns, const String16& name,
                                const String16& value)
 {
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index 86548a2..a9bea43 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -68,6 +68,8 @@
     const String16& getElementName() const;
     const Vector<sp<XMLNode> >& getChildren() const;
 
+    const String8& getFilename() const;
+    
     struct attribute_entry {
         attribute_entry() : index(~(uint32_t)0), nameResId(0)
         {
@@ -91,6 +93,8 @@
 
     const Vector<attribute_entry>& getAttributes() const;
 
+    const attribute_entry* getAttribute(const String16& ns, const String16& name) const;
+    
     const String16& getCData() const;
 
     const String16& getComment() const;
@@ -98,8 +102,14 @@
     int32_t getStartLineNumber() const;
     int32_t getEndLineNumber() const;
 
+    sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName);
+    
+    sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName);
+    
     status_t addChild(const sp<XMLNode>& child);
 
+    status_t insertChildAt(const sp<XMLNode>& child, size_t index);
+
     status_t addAttribute(const String16& ns, const String16& name,
                           const String16& value);
 
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 1dedd04..aec2164 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -5,6 +5,7 @@
 #include <vector>
 #include <set>
 #include <stdarg.h>
+#include <stdio.h>
 
 using namespace std;
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
index 3f9a993..18c0e17 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
@@ -24,8 +24,8 @@
  */
 public class Matrix extends _Original_Matrix {
 
-    float mValues[] = new float[9]; 
-    
+    float mValues[] = new float[9];
+
     /**
      * Create an identity matrix
      */
@@ -40,7 +40,7 @@
     public Matrix(Matrix src) {
         set(src);
     }
-    
+
     /**
      * Creates a Matrix object from the float array. The array becomes the internal storage
      * of the object.
@@ -50,14 +50,14 @@
         assert data.length != 9;
         mValues = data;
     }
-    
+
     @Override
     public void finalize() throws Throwable {
         // pass
     }
-    
+
     //---------- Custom Methods
-    
+
     /**
      * Adds the given transformation to the current Matrix
      * <p/>This in effect does this = this*matrix
@@ -65,17 +65,17 @@
      */
     private void addTransform(float[] matrix) {
         float[] tmp = new float[9];
-        
-        // first row 
+
+        // first row
         tmp[0] = matrix[0] * mValues[0] + matrix[1] * mValues[3] + matrix[2] * mValues[6];
         tmp[1] = matrix[0] * mValues[1] + matrix[1] * mValues[4] + matrix[2] * mValues[7];
         tmp[2] = matrix[0] * mValues[2] + matrix[1] * mValues[5] + matrix[2] * mValues[8];
-        
+
         // 2nd row
         tmp[3] = matrix[3] * mValues[0] + matrix[4] * mValues[3] + matrix[5] * mValues[6];
         tmp[4] = matrix[3] * mValues[1] + matrix[4] * mValues[4] + matrix[5] * mValues[7];
         tmp[5] = matrix[3] * mValues[2] + matrix[4] * mValues[5] + matrix[5] * mValues[8];
-        
+
         // 3rd row
         tmp[6] = matrix[6] * mValues[0] + matrix[7] * mValues[3] + matrix[8] * mValues[6];
         tmp[7] = matrix[6] * mValues[1] + matrix[7] * mValues[4] + matrix[8] * mValues[7];
@@ -84,16 +84,16 @@
         // copy the result over to mValues
         mValues = tmp;
     }
-    
+
     public AffineTransform getTransform() {
         return new AffineTransform(mValues[0], mValues[1], mValues[2],
                 mValues[3], mValues[4], mValues[5]);
     }
-    
+
     public boolean hasPerspective() {
         return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
     }
-    
+
     //----------
 
     /**
@@ -109,7 +109,7 @@
                 }
             }
         }
-        
+
         return true;
     }
 
@@ -122,7 +122,7 @@
     public boolean rectStaysRect() {
         return (computeTypeMask() & kRectStaysRect_Mask) != 0;
     }
-    
+
     /**
      * (deep) copy the src matrix into this matrix. If src is null, reset this
      * matrix to the identity matrix.
@@ -151,10 +151,10 @@
                     return false;
                 }
             }
-            
+
             return true;
         }
-        
+
         return false;
     }
 
@@ -179,7 +179,7 @@
         mValues[5] = dy;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
     }
 
     /**
@@ -200,7 +200,7 @@
         mValues[5] = -py;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
 
         // scale
         addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
@@ -219,7 +219,7 @@
         mValues[5] = 0;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
     }
 
     /**
@@ -240,13 +240,13 @@
         mValues[5] = -py;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
 
         // scale
         double rad = Math.toRadians(degrees);
         float cos = (float)Math.cos(rad);
         float sin = (float)Math.sin(rad);
-        addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 }); 
+        addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
         // translate back the pivot
         addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
     }
@@ -268,7 +268,7 @@
         mValues[5] = 0;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
     }
 
     /**
@@ -289,10 +289,10 @@
         mValues[5] = -py;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
 
         // scale
-        addTransform(new float[] { cosValue, -sinValue, 0, sinValue, cosValue, 0, 0, 0, 1 }); 
+        addTransform(new float[] { cosValue, -sinValue, 0, sinValue, cosValue, 0, 0, 0, 1 });
         // translate back the pivot
         addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
     }
@@ -308,7 +308,7 @@
         mValues[5] = 0;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
     }
 
     /**
@@ -329,7 +329,7 @@
         mValues[5] = -py;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
 
         // scale
         addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
@@ -348,7 +348,7 @@
         mValues[5] = 0;
         mValues[6] = 0;
         mValues[7] = 0;
-        mValues[7] = 1;
+        mValues[8] = 1;
     }
 
     /**
@@ -366,10 +366,10 @@
             tmp.addTransform(a.mValues);
             set(tmp);
         }
-        
+
         return true;
     }
-    
+
     @Override
     public boolean setConcat(_Original_Matrix a, _Original_Matrix b) {
         throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
@@ -384,7 +384,7 @@
         // create a matrix that will be multiply by this
         Matrix m = new Matrix(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 });
         m.addTransform(this.mValues);
-        
+
         System.arraycopy(m.mValues, 0, mValues, 0, 9);
         return true;
     }
@@ -399,7 +399,7 @@
         m.setScale(sx, sy, px, py);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -413,7 +413,7 @@
         m.setScale(sx, sy);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -427,7 +427,7 @@
         m.setRotate(degrees, px, py);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -441,7 +441,7 @@
         m.setRotate(degrees);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -455,7 +455,7 @@
         m.setSkew(kx, ky, px, py);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -469,7 +469,7 @@
         m.setSkew(kx, ky);
         m.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
 
@@ -481,10 +481,10 @@
         Matrix m = new Matrix(other);
         other.addTransform(mValues);
         set(m);
-        
+
         return true;
     }
-    
+
     @Override
     public boolean preConcat(_Original_Matrix other) {
         throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
@@ -513,7 +513,7 @@
         addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
         // translate back the pivot
         addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-        
+
         return true;
     }
 
@@ -540,10 +540,10 @@
         double rad = Math.toRadians(degrees);
         float cos = (float)Math.cos(rad);
         float sin = (float)Math.sin(rad);
-        addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 }); 
+        addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
         // translate back the pivot
         addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-        
+
         return true;
     }
 
@@ -557,7 +557,7 @@
         float cos = (float)Math.cos(rad);
         float sin = (float)Math.sin(rad);
         addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
-        
+
         return true;
     }
 
@@ -574,7 +574,7 @@
         addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
         // translate back the pivot
         addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-        
+
         return true;
     }
 
@@ -585,7 +585,7 @@
     @Override
     public boolean postSkew(float kx, float ky) {
         addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
-        
+
         return true;
     }
 
@@ -595,7 +595,7 @@
      */
     public boolean postConcat(Matrix other) {
         addTransform(other.mValues);
-        
+
         return true;
     }
 
@@ -603,7 +603,7 @@
     public boolean postConcat(_Original_Matrix other) {
         throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
     }
-    
+
     /** Controlls how the src rect should align into the dst rect for
         setRectToRect().
     */
@@ -634,7 +634,7 @@
          */
         END     (3);
 
-        // the native values must match those in SkMatrix.h 
+        // the native values must match those in SkMatrix.h
         ScaleToFit(int nativeInt) {
             this.nativeInt = nativeInt;
         }
@@ -655,7 +655,7 @@
         if (dst == null || src == null) {
             throw new NullPointerException();
         }
-        
+
         if (src.isEmpty()) {
             reset();
             return false;
@@ -689,7 +689,7 @@
                 } else {
                     diff = dst.height() - src.height() * sy;
                 }
-                
+
                 if (stf == ScaleToFit.CENTER) {
                     diff = diff / 2;
                 }
@@ -712,12 +712,12 @@
         mValues[8] = 1;
         return true;
     }
-    
+
     @Override
     public boolean setRectToRect(RectF src, RectF dst, _Original_Matrix.ScaleToFit stf) {
         throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
     }
-    
+
     /**
      * Set the matrix such that the specified src points would map to the
      * specified dst points. The "points" are represented as an array of floats,
@@ -749,7 +749,7 @@
     public boolean invert(Matrix inverse) {
         throw new UnsupportedOperationException("STUB NEEDED");
     }
-    
+
     @Override
     public boolean invert(_Original_Matrix inverse) {
         throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
@@ -772,7 +772,7 @@
         checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
         throw new UnsupportedOperationException("STUB NEEDED");
     }
-    
+
     /**
     * Apply this matrix to the array of 2D vectors specified by src, and write
      * the transformed vectors into the array of vectors specified by dst. The
@@ -790,7 +790,7 @@
         checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
         throw new UnsupportedOperationException("STUB NEEDED");
     }
-    
+
     /**
      * Apply this matrix to the array of 2D points specified by src, and write
      * the transformed points into the array of points specified by dst. The
@@ -883,7 +883,7 @@
     public float mapRadius(float radius) {
         throw new UnsupportedOperationException("STUB NEEDED");
     }
-    
+
     /** Copy 9 values from the matrix into the array.
     */
     @Override
@@ -907,7 +907,7 @@
         }
         System.arraycopy(values, 0, mValues, 0, mValues.length);
     }
-    
+
     @SuppressWarnings("unused")
     private final static int kIdentity_Mask      = 0;
     private final static int kTranslate_Mask     = 0x01;  //!< set if the matrix has translation
@@ -917,7 +917,7 @@
     private final static int kRectStaysRect_Mask = 0x10;
     @SuppressWarnings("unused")
     private final static int kUnknown_Mask       = 0x80;
-    
+
     @SuppressWarnings("unused")
     private final static int kAllMasks           = kTranslate_Mask |
                                                      kScale_Mask |
@@ -942,43 +942,43 @@
         if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
             mask |= kPerspective_Mask;
         }
-        
+
         if (mValues[2] != 0. || mValues[5] != 0.) {
             mask |= kTranslate_Mask;
         }
-    
+
         float m00 = mValues[0];
         float m01 = mValues[1];
         float m10 = mValues[3];
         float m11 = mValues[4];
-        
+
         if (m01 != 0. || m10 != 0.) {
             mask |= kAffine_Mask;
         }
-    
+
         if (m00 != 1. || m11 != 1.) {
             mask |= kScale_Mask;
         }
-        
+
         if ((mask & kPerspective_Mask) == 0) {
             // map non-zero to 1
             int im00 = m00 != 0 ? 1 : 0;
             int im01 = m01 != 0 ? 1 : 0;
             int im10 = m10 != 0 ? 1 : 0;
             int im11 = m11 != 0 ? 1 : 0;
-            
+
             // record if the (p)rimary and (s)econdary diagonals are all 0 or
             // all non-zero (answer is 0 or 1)
             int dp0 = (im00 | im11) ^ 1;  // true if both are 0
             int dp1 = im00 & im11;        // true if both are 1
             int ds0 = (im01 | im10) ^ 1;  // true if both are 0
             int ds1 = im01 & im10;        // true if both are 1
-            
+
             // return 1 if primary is 1 and secondary is 0 or
             // primary is 0 and secondary is 1
             mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
         }
-    
+
         return mask;
     }
 }
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 47a7ec0..d0a1c46 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -55,6 +55,8 @@
 import android.view.View.MeasureSpec;
 import android.view.WindowManager.LayoutParams;
 import android.widget.FrameLayout;
+import android.widget.TabHost;
+import android.widget.TabWidget;
 
 import java.lang.ref.SoftReference;
 import java.lang.reflect.Field;
@@ -69,10 +71,10 @@
  * {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}.
  */
 public final class Bridge implements ILayoutBridge {
-    
+
     private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
     private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
-    
+
     public static class StaticMethodNotImplementedException extends RuntimeException {
         private static final long serialVersionUID = 1L;
 
@@ -82,19 +84,20 @@
     }
 
     /**
-     * Maps from id to resource name/type.
+     * Maps from id to resource name/type. This is for android.R only.
      */
     private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>();
     /**
-     * Same as sRMap except for int[] instead of int resources.
+     * Same as sRMap except for int[] instead of int resources. This is for android.R only.
      */
     private final static Map<int[], String> sRArrayMap = new HashMap<int[], String>();
     /**
-     * Reverse map compared to sRMap, resource type -> (resource name -> id)
+     * Reverse map compared to sRMap, resource type -> (resource name -> id).
+     * This is for android.R only.
      */
     private final static Map<String, Map<String, Integer>> sRFullMap =
         new HashMap<String, Map<String,Integer>>();
-    
+
     private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
         new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
     private final static Map<Object, Map<String, SoftReference<NinePatch>>> sProject9PatchCache =
@@ -104,7 +107,7 @@
         new HashMap<String, SoftReference<Bitmap>>();
     private final static Map<String, SoftReference<NinePatch>> sFramework9PatchCache =
         new HashMap<String, SoftReference<NinePatch>>();
-    
+
     private static Map<String, Map<String, Integer>> sEnumValueMap;
 
     /**
@@ -156,14 +159,14 @@
 
         return sinit(fontOsLocation, enumValueMap);
     }
-    
+
     private static synchronized boolean sinit(String fontOsLocation,
             Map<String, Map<String, Integer>> enumValueMap) {
 
         // When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener
         // on static (native) methods which prints the signature on the console and
         // throws an exception.
-        // This is useful when testing the rendering in ADT to identify static native 
+        // This is useful when testing the rendering in ADT to identify static native
         // methods that are ignored -- layoutlib_create makes them returns 0/false/null
         // which is generally OK yet might be a problem, so this is how you'd find out.
         //
@@ -214,7 +217,7 @@
         } else {
             return false;
         }
-        
+
         sEnumValueMap = enumValueMap;
 
         // now parse com.android.internal.R (and only this one as android.R is a subset of
@@ -226,13 +229,13 @@
             // int[] does not implement equals/hashCode, and if the parsing used a different class
             // loader for the R class, this would NOT work.
             Class<?> r = com.android.internal.R.class;
-            
+
             for (Class<?> inner : r.getDeclaredClasses()) {
                 String resType = inner.getSimpleName();
 
                 Map<String, Integer> fullMap = new HashMap<String, Integer>();
                 sRFullMap.put(resType, fullMap);
-                
+
                 for (Field f : inner.getDeclaredFields()) {
                     // only process static final fields. Since the final attribute may have
                     // been altered by layoutlib_create, we only check static
@@ -243,7 +246,7 @@
                             // if the object is an int[] we put it in sRArrayMap
                             sRArrayMap.put((int[]) f.get(null), f.getName());
                         } else if (type == int.class) {
-                            Integer value = (Integer) f.get(null); 
+                            Integer value = (Integer) f.get(null);
                             sRMap.put(value, new String[] { f.getName(), resType });
                             fullMap.put(f.getName(), value);
                         } else {
@@ -281,7 +284,7 @@
             themeName = themeName.substring(1);
             isProjectTheme = true;
         }
-        
+
         return computeLayout(layoutDescription, projectKey,
                 screenWidth, screenHeight, DisplayMetrics.DEFAULT_DENSITY,
                 DisplayMetrics.DEFAULT_DENSITY, DisplayMetrics.DEFAULT_DENSITY,
@@ -294,6 +297,7 @@
      * (non-Javadoc)
      * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
      */
+    @Deprecated
     public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
             int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
             Map<String, Map<String, IResourceValue>> projectResources,
@@ -319,7 +323,7 @@
         if (logger == null) {
             logger = sDefaultLogger;
         }
-        
+
         synchronized (sDefaultLogger) {
             sLogger = logger;
         }
@@ -327,12 +331,12 @@
         // find the current theme and compute the style inheritance map
         Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
             new HashMap<IStyleResourceValue, IStyleResourceValue>();
-        
+
         IStyleResourceValue currentTheme = computeStyleMaps(themeName, isProjectTheme,
                 projectResources.get(BridgeConstants.RES_STYLE),
                 frameworkResources.get(BridgeConstants.RES_STYLE), styleParentMap);
-        
-        BridgeContext context = null; 
+
+        BridgeContext context = null;
         try {
             // setup the display Metrics.
             DisplayMetrics metrics = new DisplayMetrics();
@@ -347,29 +351,32 @@
                     frameworkResources, styleParentMap, customViewLoader, logger);
             BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
             context.setBridgeInflater(inflater);
-            
+
             IResourceValue windowBackground = null;
             int screenOffset = 0;
             if (currentTheme != null) {
                 windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
                 windowBackground = context.resolveResValue(windowBackground);
-    
+
                 screenOffset = getScreenOffset(currentTheme, context);
             }
-            
+
             // we need to make sure the Looper has been initialized for this thread.
             // this is required for View that creates Handler objects.
             if (Looper.myLooper() == null) {
                 Looper.prepare();
             }
-            
+
             BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
                     context, false /* platformResourceFlag */);
-            
+
             ViewGroup root = new FrameLayout(context);
-        
+
             View view = inflater.inflate(parser, root);
-            
+
+            // post-inflate process. For now this supports TabHost/TabWidget
+            postInflateProcess(view, customViewLoader);
+
             // set the AttachInfo on the root view.
             AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
                     new Handler(), null);
@@ -392,16 +399,19 @@
             // measure the views
             view.measure(w_spec, h_spec);
             view.layout(0, screenOffset, screenWidth, screenHeight);
-            
+
             // draw them
             BridgeCanvas canvas = new BridgeCanvas(screenWidth, screenHeight - screenOffset,
                     logger);
-            
+
             root.draw(canvas);
             canvas.dispose();
-            
+
             return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
                     canvas.getImage());
+        } catch (PostInflateException e) {
+            return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
+                    + e.getMessage());
         } catch (Throwable e) {
             // get the real cause of the exception.
             Throwable t = e;
@@ -419,7 +429,7 @@
             // Make sure to remove static references, otherwise we could not unload the lib
             BridgeResources.clearSystem();
             BridgeAssetManager.clearSystem();
-            
+
             // Remove the global logger
             synchronized (sDefaultLogger) {
                 sLogger = sDefaultLogger;
@@ -437,18 +447,18 @@
             sProject9PatchCache.remove(projectKey);
         }
     }
-    
+
     /**
      * Returns details of a framework resource from its integer value.
      * @param value the integer value
      * @return an array of 2 strings containing the resource name and type, or null if the id
-     * does not match any resource. 
+     * does not match any resource.
      */
     public static String[] resolveResourceValue(int value) {
         return sRMap.get(value);
-        
+
     }
-    
+
     /**
      * Returns the name of a framework resource whose value is an int array.
      * @param array
@@ -456,7 +466,7 @@
     public static String resolveResourceValue(int[] array) {
         return sRArrayMap.get(array);
     }
-    
+
     /**
      * Returns the integer id of a framework resource, from a given resource type and resource name.
      * @param type the type of the resource
@@ -468,15 +478,15 @@
         if (map != null) {
             return map.get(name);
         }
-        
+
         return null;
     }
-    
+
     static Map<String, Integer> getEnumValues(String attributeName) {
         if (sEnumValueMap != null) {
             return sEnumValueMap.get(attributeName);
         }
-        
+
         return null;
     }
 
@@ -507,13 +517,13 @@
 
         return result;
     }
-    
+
     /**
      * Compute style information from the given list of style for the project and framework.
      * @param themeName the name of the current theme.  In order to differentiate project and
      * platform themes sharing the same name, all project themes must be prepended with
      * a '*' character.
-     * @param isProjectTheme Is this a project theme 
+     * @param isProjectTheme Is this a project theme
      * @param inProjectStyleMap the project style map
      * @param inFrameworkStyleMap the framework style map
      * @param outInheritanceMap the map of style inheritance. This is filled by the method
@@ -523,23 +533,23 @@
             String themeName, boolean isProjectTheme, Map<String,
             IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap,
             Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
-        
+
         if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
             // first, get the theme
             IResourceValue theme = null;
-            
+
             // project theme names have been prepended with a *
             if (isProjectTheme) {
                 theme = inProjectStyleMap.get(themeName);
             } else {
                 theme = inFrameworkStyleMap.get(themeName);
             }
-            
+
             if (theme instanceof IStyleResourceValue) {
                 // compute the inheritance map for both the project and framework styles
                 computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
                         inFrameworkStyleMap, outInheritanceMap);
-    
+
                 // Compute the style inheritance for the framework styles/themes.
                 // Since, for those, the style parent values do not contain 'android:'
                 // we want to force looking in the framework style only to avoid using
@@ -547,11 +557,11 @@
                 // To do this, we pass null in lieu of the project style map.
                 computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
                         inFrameworkStyleMap, outInheritanceMap);
-    
+
                 return (IStyleResourceValue)theme;
             }
         }
-        
+
         return null;
     }
 
@@ -573,7 +583,7 @@
 
                 // first look for a specified parent.
                 String parentName = style.getParentStyle();
-                
+
                 // no specified parent? try to infer it from the name of the style.
                 if (parentName == null) {
                     parentName = getParentName(value.getName());
@@ -581,7 +591,7 @@
 
                 if (parentName != null) {
                     parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-                    
+
                     if (parentStyle != null) {
                         outInheritanceMap.put(style, parentStyle);
                     }
@@ -589,7 +599,7 @@
             }
         }
     }
-    
+
     /**
      * Searches for and returns the {@link IStyleResourceValue} from a given name.
      * <p/>The format of the name can be:
@@ -607,27 +617,27 @@
             Map<String, IResourceValue> inProjectStyleMap,
             Map<String, IResourceValue> inFrameworkStyleMap) {
         boolean frameworkOnly = false;
-        
+
         String name = parentName;
-        
+
         // remove the useless @ if it's there
         if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
             name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
         }
-        
+
         // check for framework identifier.
         if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
             frameworkOnly = true;
             name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
         }
-        
+
         // at this point we could have the format style/<name>. we want only the name
         if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
             name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
         }
 
         IResourceValue parent = null;
-        
+
         // if allowed, search in the project resources.
         if (frameworkOnly == false && inProjectStyleMap != null) {
             parent = inProjectStyleMap.get(name);
@@ -637,17 +647,17 @@
         if (parent == null) {
             parent = inFrameworkStyleMap.get(name);
         }
-        
+
         // make sure the result is the proper class type and return it.
         if (parent instanceof IStyleResourceValue) {
             return (IStyleResourceValue)parent;
         }
-        
+
         sLogger.error(String.format("Unable to resolve parent style name: ", parentName));
-        
+
         return null;
     }
-    
+
     /**
      * Computes the name of the parent style, or <code>null</code> if the style is a root style.
      */
@@ -656,10 +666,10 @@
         if (index != -1) {
             return styleName.substring(0, index);
         }
-        
+
         return null;
     }
-    
+
     /**
      * Returns the top screen offset. This depends on whether the current theme defines the user
      * of the title and status bars.
@@ -670,7 +680,7 @@
 
         // get the title bar flag from the current theme.
         IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
-        
+
         // because it may reference something else, we resolve it.
         value = context.resolveResValue(value);
 
@@ -679,10 +689,10 @@
                 XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
             // get value from the theme.
             value = context.findItemInStyle(currentTheme, "windowTitleSize");
-            
+
             // resolve it
             value = context.resolveResValue(value);
-            
+
             // default value
             offset = DEFAULT_TITLE_BAR_HEIGHT;
 
@@ -690,17 +700,17 @@
             if (value != null) {
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
-                    offset = (int)typedValue.getDimension(context.getResources().mMetrics);   
+                    offset = (int)typedValue.getDimension(context.getResources().mMetrics);
                 }
             }
         }
-        
+
         // get the fullscreen flag from the current theme.
         value = context.findItemInStyle(currentTheme, "windowFullscreen");
-        
+
         // because it may reference something else, we resolve it.
         value = context.resolveResValue(value);
-        
+
         if (value == null || value.getValue() == null ||
                 XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
             // FIXME: Right now this is hard-coded in the platform, but once there's a constant, we'll need to use it.
@@ -711,6 +721,94 @@
     }
 
     /**
+     * Post process on a view hierachy that was just inflated.
+     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+     * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
+     * based on the content of the {@link FrameLayout}.
+     * @param view the root view to process.
+     * @param projectCallback callback to the project.
+     */
+    private void postInflateProcess(View view, IProjectCallback projectCallback)
+            throws PostInflateException {
+        if (view instanceof TabHost) {
+            setupTabHost((TabHost)view, projectCallback);
+        } else if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup)view;
+            final int count = group.getChildCount();
+            for (int c = 0 ; c < count ; c++) {
+                View child = group.getChildAt(c);
+                postInflateProcess(child, projectCallback);
+            }
+        }
+    }
+
+    /**
+     * Sets up a {@link TabHost} object.
+     * @param tabHost the TabHost to setup.
+     * @param projectCallback The project callback object to access the project R class.
+     * @throws PostInflateException
+     */
+    private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
+            throws PostInflateException {
+        // look for the TabWidget, and the FrameLayout. They have their own specific names
+        View v = tabHost.findViewById(android.R.id.tabs);
+
+        if (v == null) {
+            throw new PostInflateException(
+                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
+        }
+
+        if ((v instanceof TabWidget) == false) {
+            throw new PostInflateException(String.format(
+                    "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
+                    "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
+        }
+
+        v = tabHost.findViewById(android.R.id.tabcontent);
+
+        if (v == null) {
+            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+            throw new PostInflateException(
+                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
+        }
+
+        if ((v instanceof FrameLayout) == false) {
+            throw new PostInflateException(String.format(
+                    "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
+                    "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
+        }
+
+        FrameLayout content = (FrameLayout)v;
+
+        // now process the content of the framelayout and dynamically create tabs for it.
+        final int count = content.getChildCount();
+
+        if (count == 0) {
+            throw new PostInflateException(
+                    "The FrameLayout for the TabHost has no content. Rendering failed.\n");
+        }
+
+        // this must be called before addTab() so that the TabHost searches its TabWidget
+        // and FrameLayout.
+        tabHost.setup();
+
+        // for each child of the framelayout, add a new TabSpec
+        for (int i = 0 ; i < count ; i++) {
+            View child = content.getChildAt(i);
+            String tabSpec = String.format("tab_spec%d", i+1);
+            int id = child.getId();
+            String[] resource = projectCallback.resolveResourceValue(id);
+            String name;
+            if (resource != null) {
+                name = resource[0]; // 0 is resource name, 1 is resource type.
+            } else {
+                name = String.format("Tab %d", i+1); // default name if id is unresolved.
+            }
+            tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
+        }
+    }
+
+    /**
      * Returns the bitmap for a specific path, from a specific project cache, or from the
      * framework cache.
      * @param value the path of the bitmap
@@ -750,7 +848,7 @@
                 map = new HashMap<String, SoftReference<Bitmap>>();
                 sProjectBitmapCache.put(projectKey, map);
             }
-            
+
             map.put(value, new SoftReference<Bitmap>(bmp));
         } else {
             sFrameworkBitmapCache.put(value, new SoftReference<Bitmap>(bmp));
@@ -767,7 +865,7 @@
     static NinePatch getCached9Patch(String value, Object projectKey) {
         if (projectKey != null) {
             Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
-            
+
             if (map != null) {
                 SoftReference<NinePatch> ref = map.get(value);
                 if (ref != null) {
@@ -780,7 +878,7 @@
                 return ref.get();
             }
         }
-        
+
         return null;
     }
 
@@ -798,13 +896,21 @@
                 map = new HashMap<String, SoftReference<NinePatch>>();
                 sProject9PatchCache.put(projectKey, map);
             }
-            
+
             map.put(value, new SoftReference<NinePatch>(ninePatch));
         } else {
             sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
         }
     }
 
+    private static final class PostInflateException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        public PostInflateException(String message) {
+            super(message);
+        }
+    }
+
     /**
      * Implementation of {@link IWindowSession} so that mSession is not null in
      * the {@link SurfaceView}.
@@ -839,7 +945,7 @@
             // pass for now.
             return false;
         }
-        
+
         @SuppressWarnings("unused")
         public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
             // pass for now.
@@ -863,7 +969,7 @@
         public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
             // pass for now.
         }
-        
+
         @SuppressWarnings("unused")
         public void remove(IWindow arg0) throws RemoteException {
             // pass for now.
@@ -883,13 +989,13 @@
                 Rect visibleInsets) {
             // pass for now.
         }
-        
+
         public IBinder asBinder() {
             // pass for now.
             return null;
         }
     }
-    
+
     /**
      * Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
      */
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
index 1fa11af..06dd96f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
@@ -59,7 +59,7 @@
     public void setConfiguration(int mcc, int mnc, String locale,
             int orientation, int touchscreen, int density, int keyboard,
             int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int version)  {
+            int screenLayout, int version)  {
         
         Configuration c = new Configuration();
         c.mcc = mcc;
@@ -70,5 +70,6 @@
         c.keyboardHidden = keyboardHidden;
         c.navigation = navigation;
         c.orientation = orientation;
+        c.screenLayout = screenLayout;
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index f434e14..69f3d9c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
@@ -960,12 +961,24 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         // TODO Auto-generated method stub
         return null;
     }
 
     @Override
+    public File getSharedPrefsFile(String name) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
     public SharedPreferences getSharedPreferences(String arg0, int arg1) {
         // TODO Auto-generated method stub
         return null;
@@ -1145,12 +1158,4 @@
     public Context getApplicationContext() {
         throw new UnsupportedOperationException();
     }
-
-    /**
-     * @hide
-     */
-    @Override
-    public float getApplicationScale() {
-        throw new UnsupportedOperationException();
-    }
 }
diff --git a/tools/localize/Android.mk b/tools/localize/Android.mk
index 186177f5..ab79f8d 100644
--- a/tools/localize/Android.mk
+++ b/tools/localize/Android.mk
@@ -53,4 +53,3 @@
 endif
 
 include $(BUILD_HOST_EXECUTABLE)
-
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 3425668..1c644ed 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -1,6 +1,7 @@
 #include "Perforce.h"
 #include "log.h"
 #include <string.h>
+#include <cstdio>
 #include <stdlib.h>
 #include <sstream>
 #include <sys/types.h>
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 9d7c5c6..2533f0a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -1,6 +1,7 @@
 #include "SourcePos.h"
 
 #include <stdarg.h>
+#include <cstdio>
 #include <set>
 
 using namespace std;
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
index e396f8b..8623b97 100644
--- a/tools/localize/Values.cpp
+++ b/tools/localize/Values.cpp
@@ -1,5 +1,6 @@
 #include "Values.h"
 #include <stdlib.h>
+#include <cstdio>
 
 
 // =====================================================================================
diff --git a/tools/localize/XLIFFFile.cpp b/tools/localize/XLIFFFile.cpp
index 51f81de..4e217d9 100644
--- a/tools/localize/XLIFFFile.cpp
+++ b/tools/localize/XLIFFFile.cpp
@@ -3,6 +3,7 @@
 #include <algorithm>
 #include <sys/time.h>
 #include <time.h>
+#include <cstdio>
 
 const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
 
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index bb82a9c5..293e50e 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -1,14 +1,49 @@
 #include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include "file_utils.h"
 #include "Perforce.h"
+#include <utils/String8.h>
 #include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <errno.h>
-#include <host/Directories.h>
 #include "log.h"
 
+using namespace android;
+using namespace std;
+
+static string
+parent_dir(const string& path)
+{
+    return string(String8(path.c_str()).getPathDir().string());
+}
+
+static int
+mkdirs(const char* last)
+{
+    String8 dest;
+    const char* s = last-1;
+    int err;
+    do {
+        s++;
+        if (s > last && (*s == '.' || *s == 0)) {
+            String8 part(last, s-last);
+            dest.appendPath(part);
+#ifdef HAVE_MS_C_RUNTIME
+            err = _mkdir(dest.string());
+#else                    
+            err = mkdir(dest.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif                    
+            if (err != 0) {
+                return err;
+            }
+            last = s+1;
+        }
+    } while (*s);
+    return 0;
+}
+
 string
 translated_file_name(const string& file, const string& locale)
 {
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 63d904c..678cad8 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,6 +1,7 @@
 #include "XLIFFFile.h"
 #include "ValuesFile.h"
 #include "localize.h"
+#include <stdio.h>
 
 int pseudolocalize_xliff(XLIFFFile* xliff, bool expand);
 
diff --git a/tools/localize/merge_res_and_xliff.cpp b/tools/localize/merge_res_and_xliff.cpp
index 58a6554..1fdaa0e 100644
--- a/tools/localize/merge_res_and_xliff.cpp
+++ b/tools/localize/merge_res_and_xliff.cpp
@@ -3,6 +3,7 @@
 #include "file_utils.h"
 #include "Perforce.h"
 #include "log.h"
+#include <stdio.h>
 
 static set<StringResource>::const_iterator
 find_id(const set<StringResource>& s, const string& id, int index)
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index 5a2b0f4..e4ab562 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,5 +1,5 @@
 #include "merge_res_and_xliff.h"
-
+#include <stdio.h>
 
 int
 merge_test()
diff --git a/tools/localize/xmb.cpp b/tools/localize/xmb.cpp
index 236705f..d8f6ff0 100644
--- a/tools/localize/xmb.cpp
+++ b/tools/localize/xmb.cpp
@@ -7,6 +7,7 @@
 #include "XLIFFFile.h"
 
 #include <map>
+#include <cstdio>
 
 using namespace std;