diff --git a/INTERNAL.md b/INTERNAL.md index 24e79772..0e2893b4 100644 --- a/INTERNAL.md +++ b/INTERNAL.md @@ -239,3 +239,22 @@ we lose the ability to quickly build just the aapt binary. So the Windows proced 1. `source build/envsetup.sh` 2. `lunch sdk-eng` 3. `make OUT_DIR=out-x64 LOCAL_MULTILIB=64 USE_NINJA=false aapt` + +# Gradle Tips n Tricks + + ./gradlew build shadowJar proguard -x test + +This skips the testing suite (which currently takes 2-4 minutes). Use this when making quick builds and save the testing +suite before pushing to GitHub. + + ./gradlew build shadowJar proguard -Dtest.debug + +This enables debugging on the test suite. This starts the debugger on port 5005 which you can connect with IntelliJ. + + ./gradlew :brut.apktool:apktool-lib:test ---tests "*BuildAndDecodeTest" + +This runs the library project of Apktool, selecting a specific test to run. Comes in handy when writing a new test and +only wanting to run that one. The asterisk is used to the full path to the test can be ignored. You can additionally +match this with the debugging parameter to debug a specific test. This command can be found below. + + ./gradlew :brut.apktool:apktool-lib:test --tests "*BuildAndDecodeTest" -Dtest.debug diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java index d51cb8d4..9c61d964 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -19,6 +19,7 @@ package brut.androlib; import brut.androlib.meta.MetaInfo; import brut.androlib.meta.UsesFramework; import brut.androlib.res.AndrolibResources; +import brut.androlib.res.data.ResConfigFlags; import brut.androlib.res.data.ResPackage; import brut.androlib.res.data.ResTable; import brut.androlib.res.data.ResUnknownFiles; @@ -279,7 +280,22 @@ public class Androlib { mAndRes.setSharedLibrary(meta.sharedLibrary); if (meta.sdkInfo != null && meta.sdkInfo.get("minSdkVersion") != null) { - mMinSdkVersion = Integer.parseInt(meta.sdkInfo.get("minSdkVersion")); + String minSdkVersion = meta.sdkInfo.get("minSdkVersion"); + + // Preview builds use short letter for API versions + switch (minSdkVersion) { + case "M": + mMinSdkVersion = ResConfigFlags.SDK_MNC; + break; + case "N": + mMinSdkVersion = ResConfigFlags.SDK_NOUGAT; + break; + case "O": + mMinSdkVersion = ResConfigFlags.SDK_O; + break; + default: + mMinSdkVersion = Integer.parseInt(meta.sdkInfo.get("minSdkVersion")); + } } if (outFile == null) { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java index 0c4aaf5f..333c3aa7 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java @@ -507,6 +507,9 @@ public class ResConfigFlags { public final static byte SDK_LOLLIPOP = 21; public final static byte SDK_LOLLIPOP_MR1 = 22; public final static byte SDK_MNC = 23; + public final static byte SDK_NOUGAT = 24; + public final static byte SDK_NOUGAT_MR1 = 25; + public final static byte SDK_O = 26; public final static byte ORIENTATION_ANY = 0; public final static byte ORIENTATION_PORT = 1; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java index aa0741d1..875142b0 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java @@ -90,7 +90,8 @@ public class ResValueFactory { if (key == ResAttr.BAG_KEY_ATTR_TYPE) { return ResAttr.factory(parentVal, items, this, mPackage); } - if (key == ResArrayValue.BAG_KEY_ARRAY_START) { + // Android O Preview added an unknown enum for ResTable_map. This is hardcoded as 0 for now. + if (key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) { return new ResArrayValue(parentVal, items); } if (key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END) { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/StringBlock.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/StringBlock.java index d6f03c8a..dd692f41 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/StringBlock.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/StringBlock.java @@ -131,8 +131,14 @@ public class StringBlock { if (style == null) { return ResXmlEncoders.escapeXmlChars(raw); } + + // If the returned style is further in string, than string length. Lets skip it. + if (style[1] > raw.length()) { + return ResXmlEncoders.escapeXmlChars(raw); + } StringBuilder html = new StringBuilder(raw.length() + 32); int[] opened = new int[style.length / 3]; + boolean[] unclosed = new boolean[style.length / 3]; int offset = 0, depth = 0; while (true) { int i = -1, j; @@ -149,6 +155,9 @@ public class StringBlock { int last = opened[j]; int end = style[last + 2]; if (end >= start) { + if (style[last + 1] == -1 && end != -1) { + unclosed[j] = true; + } break; } if (offset <= end) { @@ -160,6 +169,11 @@ public class StringBlock { depth = j + 1; if (offset < start) { html.append(ResXmlEncoders.escapeXmlChars(raw.substring(offset, start))); + if (j >= 0 && unclosed.length >= j && unclosed[j]) { + if (unclosed.length > (j + 1) && unclosed[j + 1] || unclosed.length == 1) { + outputStyleTag(getString(style[opened[j]]), html, true); + } + } offset = start; } if (i == -1) { diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/32/aapt b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/32/aapt index 72ad574b..ea1d16db 100755 Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/32/aapt and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/32/aapt differ diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/64/aapt b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/64/aapt index d09b6145..ba0a130e 100755 Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/64/aapt and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/linux/64/aapt differ diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/32/aapt b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/32/aapt index e0fc2525..80190671 100644 Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/32/aapt and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/32/aapt differ diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/64/aapt b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/64/aapt index e31b2821..327d5963 100644 Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/64/aapt and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/macosx/64/aapt differ diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/windows/aapt.exe b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/windows/aapt.exe index 10ca6130..65ffe0a6 100755 Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/windows/aapt.exe and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/aapt/windows/aapt.exe differ diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java index da251858..4a0b252b 100644 --- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java @@ -253,6 +253,11 @@ public class BuildAndDecodeTest { compareValuesFiles("values-ast/strings.xml"); } + @Test + public void androidOStringTest() throws BrutException, IOException { + compareValuesFiles("values-ast/strings.xml"); + } + @Test public void twoLetterNotHandledAsBcpTest() throws BrutException, IOException { checkFolderExists("res/values-fr"); diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-ar-rXB/strings.xml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-ar-rXB/strings.xml new file mode 100644 index 00000000..687db601 --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-ar-rXB/strings.xml @@ -0,0 +1,9 @@ + + + "‏‮Forgot‬‏ ‏‮your‬‏ ‏‮username‬‏ ‏‮or‬‏ ‏‮password?‬‏\n‏‮Visit‬‏ ‏‮google.com/accounts/recover‬‏‏‮y‬‏‏‮.‬‏" + ‏‮Forgot‬‏ ‏‮your‬‏ ‏‮username‬‏ ‏‮or‬‏ ‏‮password?‬\n.‏‮Visit‬‏ ‏‮google.com/accounts/recover‬‏‏‮y‬‏ + (string8) "‏‮Forgot‬‏ ‏‮your‬‏ ‏‮username‬‏ ‏‮or‬‏ ‏‮password?‬‏\n‏‮Visit‬‏ ‏‮google.com/accounts/recover‬‏‏‮y‬‏‏‮.‬‏" + Forgot your username or password?\nVisit google.com/accounts/recovery. + ‏‮Forgot‬‏ ‏‮your‬‏ ‏‮username‬‏ ‏‮or‬‏ ‏‮password?‬‏ + ‏‮Visit‬‏ ‏‮google.com/accounts/recover‬‏‏‮y‬‏‏‮.‬‏ + \ No newline at end of file diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml index a9adad9a..65ccbe69 100644 --- a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml @@ -31,4 +31,14 @@ bar" category=temp%temp%foo res/foo/ res/foo + [TEST STRING] + [TEST STRING] + [TEST STRING] + [TEST STRING] + TEST STRING + [Ţåþ ţö ţýþé þåššŵöŕð one two three] + [Ţåþ ţö ţýþé þåššŵöŕð one two three] + [Ţåþ ţö ţýþé þåššŵöŕð one two three] + []Ţåþ ţö ţýþé þåššŵöŕð one two three + [Ţåþ ţö ţýþé þåššŵöŕð one two three]