Comments (49)
Since v2.2
it has been patched, but this issue needs work
from androidlibrary.
Is this fixed? I've noticed there is a new version...
from androidlibrary.
Not yet
from androidlibrary.
Oh ok.
Thank you.
Please update me when it gets fixed.
from androidlibrary.
@AndroidDeveloperLB check out v3.0
.
This issue should be solved.
from androidlibrary.
Seems to be fixed according to my tests.
However, when I use the library on the large project, I get this:
More than one file was found with OS independent path 'META-INF/library_release.kotlin_module'
Please explain why this occurs when using this repository.
EDIT:
I added this to the app's gradle file:
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
exclude 'META-INF/library_release.kotlin_module'
}
But then I get this:
AGPBI: {"kind":"error","text":"Program type already present: org.apache.commons.lang3.SerializationException","sources":[{}],"tool":"D8"}
> Task :app:transformClassesAndResourcesWithR8For...Release FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithR8For...Release'.
> com.android.tools.r8.CompilationFailedException: Compilation failed to complete
I tried to delete all "build" folders. Also tried to invalidate cache. Didn't help.
from androidlibrary.
I think this type of message means an external dependency is being added multiple times. This article in StackOverflow talks about it:
https://stackoverflow.com/questions/49676155/what-does-program-type-already-present-mean/49767860
In our case:
{
"kind": "error",
"text": "Program type already present: org.apache.commons.lang3.SerializationException",
"sources": [{}],
"tool": "D8"
}
You should solve it by implementing the library excluding that package:
implementation ("com.stringcare:library:$stringcare_version") {
exclude group: 'org.apache.commons' module: 'lang3'
}
Or:
implementation ("com.stringcare:library:$stringcare_version") {
exclude group: 'org.apache.commons' module: 'commons-lang3'
}
I haven´t tested it.
from androidlibrary.
I tried adding this:
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/library_release.kotlin_module'
}
And also this:
implementation("com.stringcare:library:$stringcare_version") {
exclude group: 'org.apache.commons', module: 'lang3'
exclude group: 'commons-io', module: 'commons-io'
}
And I ran this:
./gradlew clean cleanBuildCache :app:assembleDebug
Still I have the same issue:
AGPBI: {"kind":"error","text":"Program type already present: org.apache.commons.lang3.SerializationException","sources":[{}],"tool":"D8"}
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithR8ForCalleridRelease'.
> com.android.tools.r8.CompilationFailedException: Compilation failed to complete
I just noticed that I'm on "release" build. When switching to "debug" build, I can see more information. There is this conflict:
The only thing that is related to commons-io
on the project is this one:
api 'commons-io:commons-io:2.6'
And it's the latest stable version:
https://mvnrepository.com/artifact/commons-io/commons-io
from androidlibrary.
I'm seeing the correct module name (with conflict) is commons-lang3
, so you sould use:
implementation("com.stringcare:library:$stringcare_version") {
exclude group: 'org.apache.commons', module: 'commons-lang3'
}
from androidlibrary.
Now it finally builds, but then I have a new issue. As soon as I call SC.reveal(R.string.something)
, I get this crash:
java.lang.ExceptionInInitializerError
at com....$1.run(....java:31)
Caused by: java.lang.NumberFormatException: For input string: "..."
at java.lang.Integer.parseInt(Integer.java:615)
at java.lang.Integer.parseInt(Integer.java:650)
at com.stringcare.library.CPlusLogic$Companion.revealV3(CPlusLogic.kt:128)
at com.stringcare.library.SC$Companion.reveal(SC.kt:124)
at com.stringcare.library.SC$Companion.reveal(SC.kt:107)
at com.stringcare.library.SC$Companion.reveal(SC.kt:87)
at com.stringcare.library.SC.reveal(Unknown Source:2)
...
So I think it still can't handle strings as the native string handling on Android.
I think this should be posted on a new issue though. It's not related to the original issue we talked about here.
from androidlibrary.
Looks like the value of R.string.something
string is ...
, and that's wrong.
Analyze your APK for ensuring the plugin obfuscates strings: Build
> Analyze APK
You can test it too by calling getString(R.string.something)
and check what returns.
Should return something like: 123, -4, 45, 67, -56, 3, 27..
from androidlibrary.
It's not really "...". I changed it because it's a private key :)
Putting this string into the sample I've made, it works perfectly fine.
However, when using the Analyze APK
on the large app, I don't see just numbers. I see the original string.
from androidlibrary.
I think it's a configuration problem and StringCare plugin doesn't find valid resource files.
By default, SC looks for strings in every
strings.xml
file insidesrc\main
folder of your module.
Is your string located on the default folder/file?
I mean the "default" string resource is src\main\res\values{any_locale}\strings.xml
.
If your resource file is not called strings.xml
you'll have to configure StringCare for reading more file names.
Also If your string resource is located on a different source folder, configure it.
src\other_source_folder\res\values{any_locale}\strings.xml
Check out the Configuration page for more details.
from androidlibrary.
That's true. Strings files are sent to translators, so it's bad to send them the keys too.
We have the special strings in a different file: "keys.xml".
However, we had it already set up on the previous versions of the library, as such:
stringcare {
// debug true
modules {
app {
stringFiles = ['strings.xml', "keys.xml"]
srcFolders = ['src/main']
}
}
}
It's not correct anymore ?
from androidlibrary.
You use a Windows platform and the srcFolders
array could be breaking the compilation.
I mean:
stringcare {
modules {
app {
stringFiles = ['strings.xml', "keys.xml"]
srcFolders = ['src/main'] <- windows uses \\ (double slash) while macos uses /
}
}
}
Try without the srcFolders
var, the default config for the source folder should be enougth:
stringcare {
modules {
app {
stringFiles = ['strings.xml', "keys.xml"]
}
}
}
You can try too:
stringcare {
modules {
app {
stringFiles = ['strings.xml', "keys.xml"]
srcFolders = ['src\\main']
}
}
}
from androidlibrary.
We use both MacOS and Windows.
And it's not true that Windows can't use "/". And it's on gradle, so it has its own language.
Also, as I wrote, it worked fine on the old version of Stringcare that we used before .
But I've tried just for seeing if it helps.
Removing the srcFolders = ['src/main']
or replacing it with the srcFolders = ['src\\main']
line causes the app not to be built, showing me these errors:
from androidlibrary.
Have you tried this?
srcFolders = ["src\\main"] <-- this should work
srcFolders = ["src\main"]
srcFolders = ["src/main"]
Note the double quotes "
instead of '
from androidlibrary.
Using srcFolders = ["src\\main"]
got the same issue (plus I don't think it would have worked anyway on MacOS).
Using srcFolders = ["src\main"]
got me this isssue:
Using srcFolders = ["src/main"]
, it was built fine, but crashed at runtime with the NumberFormatException as before.
from androidlibrary.
I don't know what's happening.
The KotlinSample
project uses a similar configuration:
stringcare {
debug true
main_module "app"
modules {
app {
stringFiles = ['strings.xml', "strings_extra.xml"]
srcFolders = ["src\\main", "src\\other_source"]
}
}
}
And it works fine in Windows.
from androidlibrary.
I noticed I had to delete manually the build
folder (clean
task doesn't remove all files and subfolders)
from androidlibrary.
I confirm this configuration works on macOS and Windows:
apply plugin: StringCare
stringcare {
modules {
app {
stringFiles = ["strings.xml", "strings_extra.xml"]
srcFolders = ["src${File.separator}main", "src${File.separator}other_source"]
}
}
}
Ensure you delete the build folder completely.
from androidlibrary.
OK so I used this the next lines and deleted all "build" folders manually after closing the IDE :
stringcare {
modules {
app {
stringFiles = ["strings.xml", "keys.xml"]
srcFolders = ["src${File.separator}main"]
}
}
}
And I got this error (after running the IDE again and trying to build&run the app) :
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeSyncmeappDebugResources'.
> org.codehaus.groovy.runtime.GStringImpl cannot be cast to java.lang.String
And if I use the next thing again, but with deletion of "build" folders, it still crashes :
stringcare {
// debug true
modules {
app {
stringFiles = ["strings.xml", "keys.xml"]
srcFolders = ["src/main"]
}
}
}
from androidlibrary.
I'm working on path treatment.
Meanwhile, you can try calling toString()
method over the text template:
"src${File.separator}main".toString()
from androidlibrary.
There is a new release (v3.1)
- You can use the unix separator char
/
on Windows too.
apply plugin: StringCare
stringcare {
modules {
app {
stringFiles = ["strings.xml","more_strings.xml"]
srcFolders = ["src/main", "src/other_variant_source"]
}
library {
srcFolders = ['src/other_folder/main']
}
}
}
- Added two Gradle tasks for tracing and solving possible bugs or configurations. Checkout the Task page.
from androidlibrary.
I still get the same Android resource linking failed
errors , whether I use "src${File.separator}main".toString()
or srcFolders = ["src/main"]
.
I tried to delete all "build" folders too. Didn't help.
The 0.9 version could handle the paths fine. Are you sure that's the cause to the issue?
What do you want to do with the tasks you've pointed to, exactly? I think such a thing should be contacted via email. The app isn't mine. It's of my job.
from androidlibrary.
I'm not sure because on my projects always works and pass all the tests (on Windows and macOS).
The new tasks shows too much info about the obfuscation process (located files for the given configuration, fingerprint, obfuscation test..) and should help you to find what fails.
You can send it to my mail.
Remember to add a variant with the stringcareTestObfuscate${variant}
task.
from androidlibrary.
I know. The POC works fine too. I have no idea why this doesn't work on the large app.
The link doesn't say about adding stringcareTestObfuscate variant.
Do you mean adding something like that:
productFlavors {
stringcareTestObfuscate {
//stuff here, same as on the normal app
}
}
from androidlibrary.
stringcareTestObfuscate{$variant} task
Do you mean adding something like that?
No, no. It works as the build
Gradle task:
// this would be the main task that builds all variants
gradlew.bat build
// this would be the task that builds the debug variant
gradlew.bat buildDebug
// this would be the task that builds the firstflavorSecondflavorDebug variant
gradlew.bat buildFirstflavorSecondflavorDebug
If you run gradlew.bat signingReport
you will see all the available variants for your project.
stringcarePreview task
I recomend to run this task too. It doesn't need any variant and could be helpful for solving the problem, or at least to notice what's wrong.
You can see an output sample of both task in the wiki section.
from androidlibrary.
So how do I add one for StringCare exactly?
Please just explain what to do.
from androidlibrary.
I told you where it's explained:
There is a new release (v3.1)
..
- Added two Gradle tasks for tracing and solving possible bugs or configurations. Check out the Task page.
I thought you read it.
from androidlibrary.
I've read it, but I don't understand why I don't see the task on the IDE, so I thought that maybe I need to add the task.
Please explain.
Should I just run a command?
from androidlibrary.
Yes. Run the command on terminal, in the project's directory.
from androidlibrary.
OK I've sent you via email
from androidlibrary.
You only have sent the stringcarePreview
task report, and seems to be ok. Files and strings are found.
Whats shows the stringcareTestObfuscate${variant}
task?
Choose an existing BuildVariant for this value:
Ex:
$ gradlew.bat stringcareTestObfuscateDebug
from androidlibrary.
You can write me this on email...
Anyway, sent again, this time with the output of this command.
from androidlibrary.
Found how to fix it, but it doesn't mean the issue isn't here.
I've fixed it by removing the part that lets StringCare handle "strings.xml" file.
The reason:
We don't even need it to scan this file. Only "keys.xml".
So what I have is this:
apply plugin: StringCare
stringcare {
modules {
app {
stringFiles = [ "keys.xml"]
srcFolders = ["src/main"]
}
}
}
Now it works fine, I think.
The reason the issue exists, though, is that the library ruins the resources of "strings.xml" files, even though there is no hidden="true"
anywhere in any of those files.
My guess is that it happens when there are translations being used. Not just one "strings.xml" file.
from androidlibrary.
I've noticed that it still can have issues.
We have 2 kinds of versions for the app (using build-variant), and StringCare didn't return the correct value of one of the strings in "keys.xml" correctly on the other version, so I get Gibberish instead.
I tried this (based on : https://github.com/StringCare/AndroidLibrary/wiki/Configuration#additional-resource-folders ) :
stringcare {
modules {
app {
stringFiles = ["keys.xml"]
srcFolders = ["src/main","src/the_other_app_variant"]
}
}
}
so I tried to rename the "keys.xml" file into something else on the other app, and tried again using this method. Still couldn't deal with it.
Note that there are keys on the extra app that are overriding the main app.
So what I think is that those issues are connected. Meaning that if there is a need to handle multiple files or strings from different files, it doesn't work correctly.
from androidlibrary.
I'll review why it fails with your strings.xml
file.
About the other issue you mentioned, if I understood, do have you something like this? (for example)
1º src/main/.../keys.xml
:
<resources>
<string name="grievous" hidden="true">General Kenobi</string>
</resources>
2º src/the_other_app_variant/.../keys.xml
:
<resources>
<string name="grievous" hidden="true">General Kenobi 2</string>
</resources>
from androidlibrary.
Yes, the files are are such:
app\src\main\res\values\keys.xml
And:
app\src\the_other_app_variant\res\values\keys.xml
from androidlibrary.
With the following configuration:
sourceSets {
main.res.srcDirs = ['src/main/res', 'src/other_source/res']
}
I get the normal error response for duplicating resources:
[string/grievous] C:\Users\..\KotlinSample\app\src\other_source\res\values\strings_extra.xml:
Error: Duplicate resources
And the project can't compile.
from androidlibrary.
Why did you configure sourceSets
? It should work fine without it.
I already wrote it's a different variant of the same app. The second variant should use the strings with priority of itself. Meaning that in the example you wrote, the string of grievous
will be General Kenobi 2
and not the other one.
from androidlibrary.
You have to configure the sourceSets
.
src/main/.../keys.xml
:
<resources>
<string name="grievous" hidden="true">General Kenobi</string>
</resources>
src/the_other_app_variant/.../keys.xml
:
<resources>
<string name="kenobi" hidden="true">Hello There</string>
</resources>
With no configuration you will get this error because in code you use R.string.kenobi
and it's not included in the default folder src/main/res
:
error: failed linking file resources.
Android Studio (at compilation time) only knows the default configuration, which is the following:
sourceSets {
main.res.srcDirs = ['src/main/res']
}
You can define multiple sourceSets
configurations for different flavors
and buildTypes
:
sourceSets {
productionFlavor {
main.res.srcDirs = ['src/main/res', 'src/production/res']
}
developmentFlavor {
main.res.srcDirs = ['src/main/res', 'src/dev/res']
}
}
But not repeat the same resource identifier or you will get this:
Error: Duplicate resources
Check out the official documentation for more details:
https://developer.android.com/studio/build/build-variants#configure-sourcesets
from androidlibrary.
That is incorrect. Both apps worked fine for years. The resources are shared between them, and one overrides the other. In addition, as I wrote before, StringCare worked fine with both apps on v0.9.
It even says it's automatic on the link you gave:
By default, Android Studio creates the main/ source set and directories for everything you want to share between all your build variants. However, you can create new source sets to control exactly what files Gradle compiles and packages for specific build types, product flavors (and combinations of product flavors when using flavor dimensions), and build variants.
There are no issues of "Duplicate resources" , not when we used v0.9 of StringCare, and not when we didn't use it at all.
Can you please explain what you plan that I should try, exactly?
from androidlibrary.
You should try to read the documentation better xD
That is incorrect. Both apps worked fine for years. The resources are shared between them
Between what? Resource files from the same sourceSet? Please explain me
and one overrides the other
I don't understand anything hahaha
You haven't read the documentation well.
If you list multiple directories, Gradle uses all of them to collect
sources. Because Gradle gives these directories equal priority, if
you define the same resource in more than one directory, you get an
error when merging resources. The default directory is 'src/main/res'.
You haven't understood the only thing you have read:
By default, Android Studio creates the main/ source set and directories for everything you want to share between all your build variants.
That means:
src/
main/ <-- source set
java/ <-- directory
res/ <-- directory
This is what you find when you create a new Android project.
And I told you the default (for resources) is:
sourceSets {
main.res.srcDirs = ['src/main/res']
}
On the other hand:
However, you can create new source sets to control exactly what files Gradle compiles and packages for specific build types, product flavors (and combinations of product flavors when using flavor dimensions), and build variants.
And a few lines below, the sample:
android {
...
sourceSets {
// Encapsulates configurations for the main source set.
main {
// Changes the directory for Java sources. The default directory is
// 'src/main/java'.
java.srcDirs = ['other/java']
// If you list multiple directories, Gradle uses all of them to collect
// sources. Because Gradle gives these directories equal priority, if
// you define the same resource in more than one directory, you get an
// error when merging resources. The default directory is 'src/main/res'.
res.srcDirs = ['other/res1', 'other/res2']
// Note: You should avoid specifying a directory which is a parent to one
// or more other directories you specify. For example, avoid the following:
// res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
// You should specify either only the root 'other/res1' directory, or only the
// nested 'other/res1/layouts' and 'other/res1/strings' directories.
// For each source set, you can specify only one Android manifest.
// By default, Android Studio creates a manifest for your main source
// set in the src/main/ directory.
manifest.srcFile 'other/AndroidManifest.xml'
...
}
// Create additional blocks to configure other source sets.
androidTest {
// If all the files for a source set are located under a single root
// directory, you can specify that directory using the setRoot property.
// When gathering sources for the source set, Gradle looks only in locations
// relative to the root directory you specify. For example, after applying the
// configuration below for the androidTest source set, Gradle looks for Java
// sources only in the src/tests/java/ directory.
setRoot 'src/tests'
...
}
}
}
...
And I suggested you add something like this:
sourceSets {
productionFlavor {
main.res.srcDirs = ['src/main/res', 'src/production/res']
}
developmentFlavor {
main.res.srcDirs = ['src/main/res', 'src/dev/res']
}
}
And finally you say:
There are no issues of "Duplicate resources" , not when we used v0.9 of StringCare, and not when we didn't use it at all.
StringCare doesn't have any relation with "Duplicate resources" error. If you read fine the documentation, you'll see this:
Because Gradle gives these directories equal priority, if
you define the same resource in more than one directory, you get an
error when merging resources. The default directory is 'src/main/res'
To make sure I'm correct, I've tested what I just have explained to you. I have used the KotlinSample
project.
Removing sourceSets
from KotlinSample
project you'll get this:
The strings from different sourceSets aren't detected until I add:
sourceSets {
main.res.srcDirs = ['src/main/res', 'src/other_source/res']
}
from androidlibrary.
I tried to create an empty project (without StringCare) and define two simple strings.xml
files with the same resource identifier.
<string name="app_name">TestApp</string>
<string name="app_name">TestApp zsdfvgbzsadfvb</string>
The additional string file isn't detected until I add this:
sourceSets {
main.res.srcDirs = ['src/main/res', 'src/other_source/res']
}
And after that, I got the Duplicate resources
error:
You can check it in the following project or in the KotlinSample project as was explained in the last comment:
TestApp.zip
from androidlibrary.
I don't see in your sample project that you can choose between 2 build variants of apps :
and removing the part of sourceSets
didn't affect anything. Still works fine.
You also didn't set productFlavors
. Also just one package name, which doesn't make sense if you want to make 2 different apps.
This can't be an example of 2 different apps sharing code and/or resources.
Here, I've found some samples for you to try:
https://github.com/obaro/MultipleFlavorSample.git (based on https://www.androidauthority.com/building-multiple-flavors-android-app-706436/ )
https://github.com/bmuschko/gradle-android-examples/tree/master/product-flavors
https://github.com/bkraszewski/MultiFlavorDemo (based on https://softwarehut.com/multi-flavor-apps-development-android-need/ )
Notice how they all of them don't need to set sourceSets
. The articles don't even mention it, as it's very optional.
And it was this way for years. So much that in order to import those projects and run them, you need to update them a lot .
Here, I've made the smallest sample I can think of, to show how it works :
MyApplication.zip
Also watch the video, showing that indeed it works fine, using the same string, on both apps, yet with different value:
2019-06-25_10-53-36.zip
Notice that it works fine, without errors of duplicate strings. After all, that's the whole point of variants. To be able to override the resources (and even code) , to provide an alternative way to view and use the app (example: lite vs pro) .
Why close this issue?
Maybe you want to create a new one?
from androidlibrary.
I closed the issue because it’s solved.
On the other side you try to understand how sourceSets works and it doesn’t have any relation with StringCare.
My last comment proves it.
from androidlibrary.
I didn't ask about sourceSets . I don't even use it. I said you don't need it for app flavors.
If it's not related to StringCare, please explain why it causes issues when trying to use StringCare, while building&rnning a different flavor.
I don't know what exactly "proves it", and what is "it" that was proven. The last comment doesn't have a sample code of flavors at all, so I showed a sample that does, and it works fine without any sourceSet.
Even the sample that you've provided works fine without any sourceSet, so I don't understand what is this sample for.
There is a bug in StringCare, which causes the app not being able to be built. It might be related to translations, and it might be related to flavors, and maybe to both.
In short, the bug still exists.
from androidlibrary.
It proves that (without StringCare) wrong configurations causes build errors.
Even the sample that you've provided works fine without any sourceSet, so I don't understand what is this sample for.
You don't (want to) understand anything hahaha
If you run TestApp.zip this is the first you get running the app, but you don't say it ;)
Duplicate resources
Say whatever you want, but it fails without using StringCare.
You can do a second test removing the sourceSets and trying to call a string resource on the other source from the main source. You'll get something like this:
I'm not gonna answer any more. This is a waste of time.
from androidlibrary.
Related Issues (20)
- The dependency contains Java 8 bytecode. Please enable desugaring by adding the following to build.gradle
- Bug: cannot handle build variants properly HOT 42
- java.lang.NoClassDefFoundError: Could not initialize class components.Stark HOT 23
- java.lang.NoClassDefFoundError: Could not initialize class components.Stark
- compileSdkVersion is not specified HOT 2
- Library Support HOT 2
- Obfuscation library HOT 1
- Gradle crash HOT 12
- Resource not found HOT 3
- Task 'stringcareTestObfuscateDebug' not found in root project HOT 7
- What do you think about https://pypi.org/project/DeStringCare/ ? HOT 2
- Build: failed: Index: 1, Size: 1 HOT 2
- Execution failed for task ':app:generateDebugAssets' HOT 1
- JCenter Deprecation HOT 6
- Wiki update HOT 1
- migrate from AES/ECB/PKCS5Padding to AES/GCM/NoPadding. HOT 1
- Can't open the sample HOT 2
- Manifest merger failed : Attribute application@appComponentFactory
- Is this my version issue
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from androidlibrary.