I read the gradle was written in groovy.
However my build.gradle file doesn't look like groovy.
Infact it doesn't look like a language at all.
Here's my build.gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.israelkariti.location2_1"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
compile 'com.google.android.gms:play-services-maps:10.2.1'
testCompile 'junit:junit:4.12'
}
Can someone please explain to me what's up with this syntax.
How does that syntax is a Groovy code?
And if i m missing something big than please elaborate on how this thing work.
thank you
Well, Gradle adds some magic for its DSL, but technically speaking is each Gradle script fully valid Groovy.
To understand all the things like dependencies, apply plugin: and so on, we need to learn about the different types of Gradle scripts:
Build scripts (build.gradle)
Settings scripts (settings.gradle)
Initialization scripts (e.g. init.gradle)
All these script are executed in different scopes, since they are "applied on" different objects. Gradle calls this behaviour "attaching a delegate object".
For build scripts (like the one, you asked about), this object is a Project. Now lets analyze your Gradle script:
apply plugin: 'com.android.application'
The Project interface extends the PluginAware interface, which defines an apply method taking a Map<String,?>. In Groovy, the map notation is [key:value, ...], brackets can be omitted and map keys of type String are not written in quotes. So, plugin: 'com.android.application' is nothing more but a Groovy map and its handed to the apply method.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
}
I'll continue with this part and finish with the android part, because its easier to understand this way:
dependencies is not a Gradle keyword, its simply the name of a method of the already mentioned Project interface. This method takes a Closure, which is wrapped inside the braces. Normal method call brackets are omitted again. The closure is executed on a DependencyHandler object. Now we just add dependencies to our configurations. We could use the add method and pass a configuration name and a dependency notation (and optionally a new closure).
Here starts the Gradle magic. For each existing configuration in the project's ConfigurationContainer, a new method with the name of the respective configuration is added to the DependencyHandler, so we can simply use this method instead of using add all the time. When developing for Java, these configurations and therefor methods are compile, runtime, testCompile (among others). The fileTree is, once again, just a method of the Project interface.
android {
compileSdkVersion 25
...
}
The methods defined by the Project interface are not the only available methods. Gradle plugins (like the Android plugin you are using) can add extensions or conventions. This way, properties and methods can be called like they would belong to the Project object. This is how the android part can be configured via a closure right in the build script.
Inside the android closure, some additional Gradle magic happens. You probably know that, in Groovy, one can omit the get or set part and access properties directly (while possible getters or setters are still called). Gradle also adds a method for each property with the name of the property, which can be used as setter. This way, we can call the compileSdkVersion method to set the compileSdkVersion property. Once again, brackets are omitted. This is just some syntactic sugar, which lets us omit the assignment operator.
Whenever you start a new braces level, you basically use a closure to configure an object. Sometimes a new object is created, sometimes an existing property is used. Sometimes, you need to read the documentation to understand what's happening exactly.
Related
I have faced two main problems in Android Studio. First of all I can not perform copy-paste and cut-paste (ctrl+c - ctrl+v - ctrl+x) abilities in some classes. To fix that problem, I click "invalide caches/restarts", but it breaks down again immediately.
Second problem is (I think it is related to the first problem) compiler does not recognize already defined methods and attributes. Auto suggestion etc. does not work.
The steps I've taken to try to fix the problem are;
File -> invalide caches/restarts,
File -> Power Save Mode -> Disable,
Close all opened tabs and fresh restart,
File -> Sync Project with Gradle Files,
File -> Sync with File System,
Delete JDK and reinstall,
Delete Android Studio and reinstall,
Delete already downloaded SDK files and ".Android" folder,
Disable and delete all plugins.
Checked copy-paste keymap in File -> Settings -> Keymap
Pulled the project from bitbucket to different 2 computers
Created new project, copy whole project classes with NotePad++ to
new Project
Try to convert all Java codes to Kotlin, cannot convert
Here is my system specifications; Windows 10 Home Single Language (TR), version 1909. 16 GB ram. Android Studio 3.5.3 and Gradle Version 3.5.3
I have read all post about the same problem but there is no luck (The posts are only about MAC and Linux platform).
UPDATE 1.0 ->
I have discovered that some classes cannot do the operations described above, but some classes can.
I realized that, There are no icons for classes that cannot do the operations I have described above. (Sometimes magically appears "J" icons and when I clicked another class, this J icon disappears immediately.) I think gradle or file system of Android Studio does not recognize these files as classes.
UPDATE 2.0 ->
I have noticed that when I clicked the Structure section of DuoFragment (Which has 500+ lines codes and one of the uncompiled class) cannot load anything. Is DuoFragment size is bigger to process?
Also when I checked the Build section, some processes cannot run (I do not know if this is normal or not);
Task :app:compileDebugAidl NO-SOURCE,
Task :app:compileDebugRenderscript NO-SOURCE,
Task :app:processDebugJavaRes NO-SOURCE
UPDATE 3.0 ->
Here are my Gradle files.
Project Level Gradle file :
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
App level Gradle file.
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.lotusif.dump2"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.core:core:1.1.0'
// material widgets
implementation 'com.google.android.material:material:1.2.0-alpha03'
// progress bar with text
implementation "com.github.skydoves:progressview:1.0.3"
// sequence progress
implementation 'com.github.transferwise:sequence-layout:1.0.11'
// flash bar
implementation 'com.andrognito.flashbar:flashbar:1.0.2'
// toggle - switch button
implementation 'com.github.GwonHyeok:StickySwitch:0.0.15'
// Custom Toast message
implementation 'com.github.GrenderG:Toasty:1.4.2'
// liquid effect bar
implementation 'com.mikhaellopez:circularfillableloaders:1.3.2'
// bubble tab bar
implementation 'com.fxn769:bubbletabbar:1.0.3'
//glide image library
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
// scaling layout
implementation 'com.github.iammert:ScalingLayout:1.2.1'
// lottie animation
implementation 'com.airbnb.android:lottie:3.3.1'
//Gson
implementation 'com.google.code.gson:gson:2.8.6'
//RxJava
implementation 'io.reactivex.rxjava2:rxjava:2.2.15'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.daimajia.easing:library:2.1#aar'
implementation 'com.daimajia.androidanimations:library:2.3#aar'
//retrofit
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
}
UPDATE 1.0 Images
UPDATE 2.0 Images
UPDATE --> There is a bug in Kotlin libraries with Windows 10 Single Language Turkish. (Maybe some of other Single Language Windows distributions have same issue, I haven't known yet.) Kotlin's some libraries cannot work on Turkish operating system. I solved this problem with installing Windows 10 Pro English.
Other developers who use Windows 10 Single Language Turkish faces same problem with different angles. (Example1 and Example2)
OLD ANSWER
TL;DR -> Problem is about third party libraries that are written with Kotlin. I have converted my Java project to Kotlin and all problematic third party libraries work well. Problem is about Java - Kotlin conflict.
I would like to share how I solved the problem for those who will face such problems later.
I did all the steps I mentioned above one by one but I could not find any solution and I decided to examine my third party libraries.
First of all, I disabled all third party libraries and looked at the status of my classes that did not recognize already defined methods and attributes. After disabling third party libraries and making Rebuild Project and Sync Gradle, the Auto Suggestion feature of those corrupted classes started working again.Then, uncovering which third-party libraries were problematic, I activated those third-party libraries one by one. I found which third party libraries broke my project.
There were 4 third party libraries that broke my project : StickySwitch, ProgressView, SequenceLayout and Flashbar. When I removed those libraries, everything worked right. After removed the libraries, my Gradle file was as below.
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.lotusif.dump2"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.core:core:1.1.0'
// material widgets
implementation 'com.google.android.material:material:1.2.0-alpha03'
// progress bar with text BUGGY!
// implementation "com.github.skydoves:progressview:1.0.3"
// sequence progress BUGGY !
// implementation 'com.github.transferwise:sequence-layout:1.0.11'
// flash bar BUGGY !
// implementation 'com.andrognito.flashbar:flashbar:1.0.2'
// toggle - switch button BUGGY !
// implementation 'com.github.GwonHyeok:StickySwitch:0.0.15'
// Custom Toast message
implementation 'com.github.GrenderG:Toasty:1.4.2'
// liquid effect bar
implementation 'com.mikhaellopez:circularfillableloaders:1.3.2'
// bubble tab bar
implementation 'com.fxn769:bubbletabbar:1.0.3'
// android chart library
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
//glide image library
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
// scaling layout
implementation 'com.github.iammert:ScalingLayout:1.2.1'
// lottie animation
implementation 'com.airbnb.android:lottie:3.3.1'
//Gson
implementation 'com.google.code.gson:gson:2.8.6'
//RxJava
implementation 'io.reactivex.rxjava2:rxjava:2.2.15'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.daimajia.easing:library:2.1#aar'
implementation 'com.daimajia.androidanimations:library:2.3#aar'
//retrofit
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
}
So, what was the common feature of those libraries that corrupt my project? My project was written with Java but that libraries were written with Kotlin. One second, cannot I use Kotlin libraries in my Java project? Yes, I can. I have to add android.useAndroidX=true and android.enableJetifier=true in my gradle.properties, that is it. But what if I have already added those lines in my gradle.properties and it has not worked?
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
I have not understood why kotlin libraries cannot work with my Java project. As you can see in my Gradle file, I am using apply plugin: 'kotlin-android' and apply plugin: 'kotlin-android-extensions' for Kotlin support.
How I have rescued my project? There were 2 available options as I knew. While first method was that to removed those 4 third party libraries and could not use them, second one that to convert all Java classes to Kotlin classes (I tried it before but it did not work until disabled all third party libraries). I chose to convert all Java classes to Kotlin classes. Thus, I was able to use 4 third party libraries which were mentioned above.
It took me 30 days to solve this problem. Now, I am working on Kotlin language. As a result, my project is running without any problem.
I am working on a multi-module project and this project should have a Java Library module called test-shared to provide common test classes. However, I am facing an issue in which my module doesn't recognize dependencies and I cannot write my classes.
Things have been done
Enable offline mode and disable again.
Delete .gradle folder and sync.
Googled identical issues.
Invalidate cache & restart.
As a result, I don't have a working project. Your help would be welcome.
build.gradle
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.2"
implementation "androidx.test:rules:1.2.0"
implementation "androidx.lifecycle:lifecycle-runtime:2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.1.0"
}
sourceCompatibility = "8"
targetCompatibility = "8"
Example class
class Co {
val a = LiveData<Co>()
val b = Observer<Co>()
}
In this example, neither LiveData nor Observer are recognized. Could you please help me fix this weird issue?
Thanks,
If this is not the entirety of your library's gradle file, then you are missing the android plugins.
Please add the following at the top of your library's gradle file.
apply plugin: "com.android.library"
I will also recommend having a look at the documentation: https://developer.android.com/studio/projects/android-library
What is the apt dependency scope in android gradle files i see sometimes ?
An example looks like this?
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 20
buildToolsVersion '20.0.0'
defaultConfig {
applicationId "org.ligboy.test.card.module1"
minSdkVersion 14
targetSdkVersion 20
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
final DAGGER_VERSION = '2.0.2'
dependencies {
compile "com.google.dagger:dagger:${DAGGER_VERSION}"
apt "com.google.dagger:dagger-compiler:${DAGGER_VERSION}"//what is this scope
provided 'org.glassfish:javax.annotation:10.0-b28'
}
and in the top level build.gradle file it has this global dependency:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
}
Notice in the dependencies section there is a apt scope ? i only know of compile, package and provided scope. compile
includes the dependency at compile time and in your package, provided says only include the library at compile time and discard it at
package time so its not included in final build. and Package is the reverse, it includes the dependency in the package and not at compile time.
But what is apt dependency scope which we obviously need the com.neenbedankt.android-apt for it to work so i know its android based.
update:
why cant i use provided dependency scope instead of apt scope ? How do they differ ?
i created a tutorial on dagger dependency scopes for those who need more info.
From the android-apt project page:
The android-apt plugin assists in working with annotation processors in combination with Android Studio. It has two purposes:
Allow to configure a compile time only annotation processor as a dependency, not including the artifact in the final APK or library
Set up the source paths so that code that is generated from the annotation processor is correctly picked up by Android Studio.
You are using Dagger, which uses annotation processing to generate code. The annotation processing code shouldn't be included in the final APK, and you want the generated code to be visible to Android Studio. android-apt enables this behavior.
This sounds very similar to the provided scope, but apt differs from provided in a few key ways. The first difference is that code generated by an apt dependency is available to the IDE, whereas code generated by a provided dependency is not.
Another important difference is that the code in a library using the provided scope is on the IDE classpath (i.e. you can import the classes and attempt to use them), whereas code in an apt dependency is not. With provided, your code will crash at runtime if you don't actually provide the referenced dependencies with a compile scoped counterpart.
You can find a discussion about apt vs provided on this android-apt issue.
In the case of Dagger, there should be no reason to include the annotation processor and code generator in any of your code (which the provided scope would allow). Thus the apt scope is more appropriate.
Update for October 2016:
You probably don't need apt and the android-apt plugin anymore. Version 2.2 of the Android Gradle plugin has an annotationProcessor configuration that you should be using instead.
See more at What's next for android-apt?
Just to add how to change this in Studio 2.2 +
dependencies {
compile 'com.google.dagger:dagger:2.4'
annotationProcessor "com.google.dagger:dagger-compiler:2.4"
}
Add this in apps gradle module. No need to change any other thing.
Happy coding :)
Is there a reasonably simple way for a module's build.gradle file to indicate that certain files from a dependency should be excluded? I am specifically interested in excluding certain resources from an AAR.
LeakCanary is an interesting library for helping to track down memory leaks. However, it has an undocumented requirement of compileSdkVersion of 21 or higher. While most projects should not have a problem with this, it's unseemly for a library to require a certain compileSdkVersion without a good reason. A development team may have frozen their compileSdkVersion as part of a general policy to only change those sorts of settings as part of major version updates of their app or something.
In this case, for v1.3.1 of LeakCanary at least, the only reason compileSdkVersion is required, AFAICT, is because the AAR has a res/values-v21/ directory, containing a theme definition that inherits from Theme.Material. This theme is used by a diagnostic activity. That activity is never seen by end users, only by developers in debug builds. Frankly, what that activity looks like, theme-wise, does not really matter. Forcing a compileSdkVersion of 21 just to have that diagnostic activity have a certain theme is, IMHO, stupid.
It'd be nice if as part of a compile directive we could say "hey, please skip res/values-v21/ from this AAR, m'kay?". Since the -v21 theme is simply providing an alternative definition of a theme defined elsewhere, dropping the -v21 theme will not break the build or break things at runtime, but merely will give us a Holo-themed diagnostic activity.
I fail to see how this answer works with dependencies. I am also uncertain if it is complete, and it certainly does not appear to be supported. It also doesn't really qualify as "simple" — I would not expect somebody to try dropping this in a build.gradle file just to block a single file from a diagnostic library like LeakCanary.
So, is there something simpler than this that works with now-current editions of the Android Plugin for Gradle?
EDIT:
Wrote advanced gradle task for you:
final List<String> exclusions = [];
Dependency.metaClass.exclude = { String[] currentExclusions ->
currentExclusions.each {
exclusions.add("${getGroup()}/${getName()}/${getVersion()}/${it}")
}
return thisObject
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile ('com.android.support:appcompat-v7:20.+')
debugCompile ('com.squareup.leakcanary:leakcanary-android:1.3.1')
.exclude("res/values-v21/values-v21.xml")
releaseCompile ('com.squareup.leakcanary:leakcanary-android-no-op:1.3.1')
}
tasks.create("excludeTask") << {
exclusions.each {
File file = file("${buildDir}/intermediates/exploded-aar/${it}")
println("Excluding file " + file)
if (file.exists()) {
file.delete();
}
}
}
tasks.whenTaskAdded({
if (it.name.matches(/^process.*Resources$/)) {
it.dependsOn excludeTask
}
})
Now you can use method .exclude() on each dependency, providing into list of paths, you want to exclude from specified dependency.
Also, you can stack the .exclude() method calls.
I believe you can solve this problem more elegantly using the PackagingOptions facility of the Android Gradle Plugin DSL.
I was able to use this myself to exclude some native libraries I didn't need introduced by an AAR in my project.
android {
...
packagingOptions {
exclude '/lib/armeabi-v7a/<file_to_exclude>'
}
}
For the case outlined in the question, I believe this would work:
android {
...
packagingOptions {
exclude '/res/values-v21/<file_to_exclude>'
}
}
Try compileOnly keyword to mark the resource is used for compile only.
dependencies {
compileOnly fileTree(include: ['*.jar'], dir: 'libs')
}
I'm a newbie in Android especially for libs.
I'm using Android Studio 1.2.2
I'm trying to create a jar library with no activity, resources, etc (only code) that use the AltBeacon library. When complete I whould like to include this jar in my APP that has to use beacons through my lib.
Well, using AltBeacon instructions, I'm able configure gradle to have a "normal" (with activity etc) APP using AltBeacon library. But I'm not able to create a jar library that contains the AltBeacon one.
I google a lot especially in SO, I found a lot of questions about "library inside library" but that doesn't worked for me.
I made this:
I created an empty project with Studio (blank activity)
Then I created a new module -> Java Library and called it libmebeaconmanager and Studio created a new Java class that I called MeBeaconManager
I modified the build.gradle of the library in this way:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.altbeacon:android-beacon-library:2+'
}
This is the build.gradle of Module:app:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "23.0.0 rc2"
defaultConfig {
applicationId "me.padovame.libbeacontest"
minSdkVersion 18
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
}
And this is the build.gradle of project:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
At this point, in the MeBeaconManager class of the lib, I tried to import AltBeacon classes without success because I got an undefined symbol error for import lines like this:
import org.altbeacon.beacon.Beacon;
I also tried, without success, inserting in lib folder of libmebeaconmanager the downloaded android-beacon-library-2.3.aar
What am I doing wrong?
Thanks in advance.
EDIT:
I tried to include a jar (tried with Picasso) library in my libmebeaconmanager and it worked. So the problem seems to be with aar libs.
I'm going crazy...
EDIT 2:
I extracted classes.jar from the AltBeacon aar lib and used as other jar and it worked.
But I consider this as a workaround: I still do not understand how to manage directly aar files. So thanks to whom can help me.
Seems like there is a problem in inserting library to project structure
You can have a look at answer provided by user Sam Rad here:
How do I add a library project to Android Studio?