diff --git a/README.md b/README.md
new file mode 100644
index 0000000..56c9370
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+# Android Avanzado
+
+## :wave: Bienvenid@s
+
+## :dart: Objetivo
+
+Construir una aplicación Android con funciones inyectadas por dependencias y librerías, con simplificación de autenticación, reporte y seguimiento de errores, servicios de terceros, elementos de realidad aumentada, y publicable en tiendas alternativas a Google Play y/o en un servidor propio.
+
+## Datos relevantes
+
+- Firebase es una plataforma de Google para desarrollar y facilitar la creación de apps con alta calidad de una forma rápida.
+- ArCore es un kit de desarrollo de software para dispositivos móviles que permite la creación de aplicaciones de realidad aumentada.
+- Jetpack es un conjunto de bibliotecas que ayuda a los desarrolladores a seguir las prácticas recomendadas, reducir el código estándar y escribir código que funcione de manera coherente en los dispositivos y las versiones de Android, para que puedan enfocarse en el código que les interesa.
+
+## :gear: Requerimientos
+
+- Android Studio
+- Cuenta de Google
+- Teléfono físico (Recomendado)
+- SDK ArCore
+
+## 💻 Proyecto
+
+Desarrollar una app Android con Kotlin como principal lenguaje de desarrollo, con funciones agregadas mediante Firebase Authentication, Firebase Crashlytics, Dependencias, Navigation, SDK´s, Deploys, Librerías y RA.
+
+## :bookmark_tabs: Sesiones
+
+1. [Firebase Authentication ](./Sesion-01)(Simplifica el inicio de sesión y el registro)
+2. [Firebase Crashlytics ](./Sesion-02)(Reportes y seguimiento a errores)
+3. [Dependencias ](./Sesion-03)(Simplifica el código)
+4. [Navigation ](./Sesion-04)(Mejora el flujo de datos)
+5. [Terceros ](./Sesion-05)(Implementar SDK's de terceros) Facebook, Spotify, Conekta
+6. [Deploys ](./Sesion-06)(Publica en tiendas altenativas a Google Play o en un servidor externo)
+7. [Librerías ](./Sesion-07)(Ahorra código y mejora el flujo)
+8. [RA ](./Sesion-08)(Implementaciones más utilizadas de RA)
diff --git a/Sesion-01/Ejemplo-01/README.md b/Sesion-01/Ejemplo-01/README.md
new file mode 100644
index 0000000..344f64a
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/README.md
@@ -0,0 +1,58 @@
+# Ejemplo 01: Implementar Firebase Authentication
+
+## Objetivo
+
+* Implementar y configurar Firebase Authentication en un proyecto base.
+
+## Desarrollo
+
+A partir de un proyecto de Android previamente creado se implementará el BaaS de Firebase Authentication para integrar sus servicios de registro e inicio de sesión.
+
+Usaremos el [Proyecto base](./base) y le modificaremos lo que se requiera. Para hacerlo realiza los siguientes pasos:
+
+1. Ejecutamos el proyecto base con Android Studio. Este desplegará la siguiente interfaz.
+
+
+
+
+2. Ahora, agregaremos las librerías de Firebase. Para ello hacemos clic en la siguiente ruta: **Tools -> Firebase**
+
+
+
+3. El resultado será la siguiente ventana. Es necesario identificar la opción de Authentication, hacer clic en ella, y después hacer clic en la tercera opción, enlistada como **Authentication using a custom authentication system**.
+
+
+
+4. Aparecerá la siguiente ventana. Se debe hacer clic en **Connect to Firebase**.
+
+
+
+
+
+5. El resultado del botón abrirá el navegador. En la siguiente ventana debe seleccionarse el proyecto (el cual denominamos Bedu), y posteriormente es necesario hacer clic en **Conectar**.
+
+
+
+6. Listo, hasta este paso la app ya se encuentra conectada a Firebase.
+
+
+
+7. Ahora debe seguirse la ruta hasta el paso 3. Ahí debe seleccionarse **Add the Firebase Authentication SDK to your app** y luego se aceptan los cambios.
+
+
+
+ Esto Agrega *Play Services y Auth*
+
+
+
+8. Ahora debemos dirigirnos a Firebase Console y activar **Authentication**.
+
+
+
+
+
+¡Felicidades! Ya implementaste Firebase Authentication en tu proyecto Android.
+
+
+
+[Siguiente ](../Ejemplo-02/README.md)(Ejemplo 2)
diff --git a/Sesion-01/Ejemplo-01/assets/01.png b/Sesion-01/Ejemplo-01/assets/01.png
new file mode 100644
index 0000000..024d413
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/01.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/02.png b/Sesion-01/Ejemplo-01/assets/02.png
new file mode 100644
index 0000000..8e48756
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/02.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/03.png b/Sesion-01/Ejemplo-01/assets/03.png
new file mode 100644
index 0000000..c91a0b6
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/03.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/04.png b/Sesion-01/Ejemplo-01/assets/04.png
new file mode 100644
index 0000000..416ffca
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/04.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/05.png b/Sesion-01/Ejemplo-01/assets/05.png
new file mode 100644
index 0000000..b283196
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/05.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/06.png b/Sesion-01/Ejemplo-01/assets/06.png
new file mode 100644
index 0000000..d30f55c
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/06.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/07.png b/Sesion-01/Ejemplo-01/assets/07.png
new file mode 100644
index 0000000..bfcc45c
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/07.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/08.png b/Sesion-01/Ejemplo-01/assets/08.png
new file mode 100644
index 0000000..bd8b4a4
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/08.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/09.png b/Sesion-01/Ejemplo-01/assets/09.png
new file mode 100644
index 0000000..9b65d14
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/09.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/10.png b/Sesion-01/Ejemplo-01/assets/10.png
new file mode 100644
index 0000000..d0a5fa1
Binary files /dev/null and b/Sesion-01/Ejemplo-01/assets/10.png differ
diff --git a/Sesion-01/Ejemplo-01/assets/README.md b/Sesion-01/Ejemplo-01/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/.gitignore b/Sesion-01/Ejemplo-01/base/.gitignore
new file mode 100644
index 0000000..426a199
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/.gitignore
@@ -0,0 +1,14 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/.gitignore b/Sesion-01/Ejemplo-01/base/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/build.gradle b/Sesion-01/Ejemplo-01/base/app/build.gradle
new file mode 100644
index 0000000..4b5678c
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ applicationId "com.bedu.auth"
+ minSdkVersion 19
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ buildFeatures {
+ viewBinding true
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'com.google.android.material:material:1.3.0'
+
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/proguard-rules.pro b/Sesion-01/Ejemplo-01/base/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt b/Sesion-01/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..b5e9233
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.bedu.auth
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.bedu.auth", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/AndroidManifest.xml b/Sesion-01/Ejemplo-01/base/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..10c2861
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt
new file mode 100644
index 0000000..40146eb
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt
@@ -0,0 +1,33 @@
+package com.bedu.auth.utils
+
+import android.content.Context
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorRes
+import androidx.core.content.ContextCompat
+import com.bedu.auth.R
+import com.google.android.material.snackbar.Snackbar
+
+object Utility {
+
+ //display SnackBar
+ fun displaySnackBar(view: View, s: String, context: Context, @ColorRes colorRes: Int) {
+
+ Snackbar.make(view, s, Snackbar.LENGTH_LONG)
+ .withColor(ContextCompat.getColor(context, colorRes))
+ .setTextColor(ContextCompat.getColor(context, R.color.white))
+ .show()
+
+ }
+
+ fun View.hideKeyboard() {
+ val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputManager.hideSoftInputFromWindow(windowToken, 0)
+ }
+
+ private fun Snackbar.withColor(@ColorInt colorInt: Int): Snackbar {
+ this.view.setBackgroundColor(colorInt)
+ return this
+ }
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt
new file mode 100644
index 0000000..91ef1fc
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt
@@ -0,0 +1,92 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import androidx.core.widget.doAfterTextChanged
+import com.bedu.auth.databinding.ActivityEmailBinding
+import com.bedu.auth.utils.Utility.hideKeyboard
+
+class EmailActivity : Activity() {
+
+ private lateinit var binding: ActivityEmailBinding
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityEmailBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ handleClick()
+ }
+
+ private fun handleClick() {
+
+ binding.btnLogin.setOnClickListener {
+ it.hideKeyboard()
+
+ binding.btnLogin.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ signIn(email, password)
+ }
+ binding.btnRegister.setOnClickListener {
+ it.hideKeyboard()
+
+ binding.btnLogin.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ createAccount(email, password)
+ }
+
+ binding.editText.doAfterTextChanged {
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ binding.btnLogin.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ binding.btnRegister.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ }
+
+ binding.editText2.doAfterTextChanged {
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ binding.btnLogin.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ binding.btnRegister.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ }
+ }
+
+ private fun createAccount(email: String, password: String) {
+ updateUI()
+ }
+
+ private fun signIn(email: String, password: String) {
+ updateUI()
+ }
+
+ private fun sendEmailVerification() {
+ }
+
+ private fun updateUI() {
+ Handler(Looper.getMainLooper()).postDelayed({
+ binding.loading.visibility = View.GONE
+ binding.btnLogin.visibility = View.VISIBLE
+ }, 2000)
+ }
+
+ private fun reload() {
+
+ }
+
+ companion object {
+ private const val TAG = "EmailPassword"
+ }
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt
new file mode 100644
index 0000000..eff0193
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt
@@ -0,0 +1,51 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import com.bedu.auth.databinding.ActivityOptionsBinding
+
+class MainActivity : Activity() {
+
+ private lateinit var binding: ActivityOptionsBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityOptionsBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ handleClick()
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ }
+
+ private fun handleClick() {
+
+ binding.btnEmail.setOnClickListener {
+ val intent = Intent(this, EmailActivity::class.java)
+ startActivity(intent)
+ }
+ binding.btnPhone.setOnClickListener {
+ val intent = Intent(this, PhoneActivity::class.java)
+ startActivity(intent)
+ }
+ binding.btnGoogle.setOnClickListener {
+ }
+ }
+
+
+
+ private fun updateUI() {
+
+ }
+
+ companion object {
+ private const val TAG = "GoogleActivity"
+ private const val RC_SIGN_IN = 9001
+ }
+
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt
new file mode 100644
index 0000000..63d28e2
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt
@@ -0,0 +1,90 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import androidx.core.widget.doAfterTextChanged
+import com.bedu.auth.databinding.ActivityPhoneBinding
+import com.bedu.auth.utils.Utility.hideKeyboard
+
+
+class PhoneActivity : Activity() {
+
+ private lateinit var binding: ActivityPhoneBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityPhoneBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ binding.btnContinue.setOnClickListener {
+ it.hideKeyboard()
+
+ val phone = binding.edtPhone.text.toString()
+
+ when {
+ binding.btnContinue.text == "Resend code" -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtCode.text.clear()
+ resendVerificationCode(phone, "resendToken")
+ binding.btnContinue.text = "Continue"
+ }
+ binding.edtPhone.visibility == View.VISIBLE -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtPhone.visibility = View.INVISIBLE
+
+ startPhoneNumberVerification(phone)
+ }
+ binding.edtCode.text.isNotEmpty() -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtCode.visibility = View.GONE
+
+ val code = binding.edtCode.text.toString()
+
+ verifyPhoneNumberWithCode("verificationId", code)
+ }
+ }
+ }
+
+ binding.edtPhone.doAfterTextChanged {
+ val phone = binding.edtPhone.text.toString()
+
+ binding.btnContinue.isEnabled = phone.isNotEmpty()
+ }
+ }
+
+ private fun startPhoneNumberVerification(phoneNumber: String) {
+ updateUI()
+ }
+
+ private fun verifyPhoneNumberWithCode(verificationId: String, code: String) {
+ updateUI()
+ }
+
+ private fun resendVerificationCode(
+ phoneNumber: String,
+ token: String
+ ) {
+ updateUI()
+ }
+ // [END resend_verification]
+
+ private fun updateUI() {
+ Handler(Looper.getMainLooper()).postDelayed({
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.loading.visibility = View.GONE
+ binding.edtPhone.visibility = View.VISIBLE
+ }, 2000)
+ }
+
+ companion object {
+ private const val TAG = "PhoneAuthActivity"
+ }
+
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml
new file mode 100644
index 0000000..c6c847c
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml
new file mode 100644
index 0000000..95e5851
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml
new file mode 100644
index 0000000..797bc91
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/values-night/themes.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..81fd680
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/values/colors.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..ceeb872
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/colors.xml
@@ -0,0 +1,13 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
+ #c90606
+ #008000
+
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/values/strings.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b6cfb0f
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Auth
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/main/res/values/themes.xml b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..72400e8
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt b/Sesion-01/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt
new file mode 100644
index 0000000..3cbca35
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.bedu.auth
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/build.gradle b/Sesion-01/Ejemplo-01/base/build.gradle
new file mode 100644
index 0000000..3194816
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/build.gradle
@@ -0,0 +1,26 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ext.kotlin_version = "1.5.10"
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/gradle.properties b/Sesion-01/Ejemplo-01/base/gradle.properties
new file mode 100644
index 0000000..2521752
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# 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
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar b/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties b/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..47e2a92
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Jun 05 12:34:09 CDT 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/Sesion-01/Ejemplo-01/base/gradlew b/Sesion-01/Ejemplo-01/base/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/Sesion-01/Ejemplo-01/base/gradlew.bat b/Sesion-01/Ejemplo-01/base/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Sesion-01/Ejemplo-01/base/settings.gradle b/Sesion-01/Ejemplo-01/base/settings.gradle
new file mode 100644
index 0000000..ac84e05
--- /dev/null
+++ b/Sesion-01/Ejemplo-01/base/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "Auth"
+include ':app'
diff --git a/Sesion-01/Ejemplo-02/README.md b/Sesion-01/Ejemplo-02/README.md
new file mode 100644
index 0000000..1a5dc1e
--- /dev/null
+++ b/Sesion-01/Ejemplo-02/README.md
@@ -0,0 +1,101 @@
+# Ejemplo 02: Registro con correo y contraseña
+
+## Objetivo
+
+* Operar el registro con una cuenta de correo electrónico y una contraseña mediante la conexión de la interfaz con las llamadas de Auth, y establecer la notificación al usuario con las respuestas de Auth.
+
+## Desarrollo
+
+A partir del proyecto de Android previamente creado se simulará la creación de una cuenta con un correo electrónico y una contraseña.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Entra a Firebase Console. Dentro del menú Authentication haz clic en *Configurar el método de acceso*, como se visualiza en la siguiente imagen.
+
+
+
+2. Selecciona Correo electrónico / contraseña como método de acceso.
+
+
+
+3. Posteriormente es necesario habilitar el primer check, y con el segundo desactivado haremos clic en Guardar como se visualiza en la imagen siguiente.
+
+
+
+4. Nos dirigiremos al Gradle del proyecto. Ahí agregamos las siguientes dependencias y después hacemos clic en **Sync Now**.
+
+ ```kotlin
+ implementation platform('com.google.firebase:firebase-bom:28.0.1')
+ implementation 'com.google.firebase:firebase-auth-ktx'
+ ```
+
+5. Ahora modificamos la clase **MainActivity** de la siguiente manera.
+
+ Inicializando FirebaseApp
+
+ ```kotlin
+ //Dentro de onCreate
+ FirebaseApp.initializeApp(this)
+ ```
+
+6. Después modificamos **EmailActivity** de la siguiente manera.
+
+ ```kotlin
+ //Declaramos la variable
+ private lateinit var auth: FirebaseAuth
+ ```
+
+ ```kotlin
+ //Dentro de onCreate
+ auth = Firebase.auth
+ ```
+
+7. En suma, agregamos la siguiente llamada a la función **createAccount** para registrar el correo y la contraseña que escribió el usuario en la interfaz.
+
+ ```kotlin
+ auth.createUserWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ Log.d(TAG, "createUserWithEmail:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ Log.w(TAG, "createUserWithEmail:failure", task.exception)
+ updateUI(null, task.exception)
+ }
+ }
+ ```
+
+8. Asimismo, en ambas respuestas, **(success - failure)**, llamamos a la función **updateUI**, la cual se encargará de mostrar los mensajes, así que la reemplazamos con el siguiente bloque de código.
+
+ ```kotlin
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ if (exception != null) {
+ binding.loading.visibility = View.GONE
+ binding.btnLogin.visibility = View.VISIBLE
+ Utility.displaySnackBar(binding.root, exception.message.toString(), this, R.color.red)
+ } else {
+ Utility.displaySnackBar(binding.root, "Login was successful", this, R.color.green)
+ binding.loading.visibility = View.GONE
+ binding.btnLogin.visibility = View.VISIBLE
+ }
+ }
+ ```
+
+9. Es momento de ejecutar la app y registrar una cuenta, como en la siguiente imagen.
+
+
+
+ Después de unos segundos deberíamos ver el siguiente mensaje en la app.
+
+
+
+10. Además, verifica el registro del usuario en la pestaña users de Firebase Console. Ahí debería figurar, como en la siguiente imagen.
+
+
+
+¡Felicidades! Ahora tu app puede registrar usuarios sin agregar código en el servidor.
+
+
+
+[Siguiente ](../Reto-01/README.md)(Reto 1)
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-02/assets/01.png b/Sesion-01/Ejemplo-02/assets/01.png
new file mode 100644
index 0000000..4eec739
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/01.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/02.png b/Sesion-01/Ejemplo-02/assets/02.png
new file mode 100644
index 0000000..5ce8bfa
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/02.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/03.png b/Sesion-01/Ejemplo-02/assets/03.png
new file mode 100644
index 0000000..b6eec03
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/03.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/04.png b/Sesion-01/Ejemplo-02/assets/04.png
new file mode 100644
index 0000000..e8a2a8a
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/04.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/05.png b/Sesion-01/Ejemplo-02/assets/05.png
new file mode 100644
index 0000000..b8a8eac
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/05.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/06.png b/Sesion-01/Ejemplo-02/assets/06.png
new file mode 100644
index 0000000..b065143
Binary files /dev/null and b/Sesion-01/Ejemplo-02/assets/06.png differ
diff --git a/Sesion-01/Ejemplo-02/assets/README.md b/Sesion-01/Ejemplo-02/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-01/Ejemplo-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-03/README.md b/Sesion-01/Ejemplo-03/README.md
new file mode 100644
index 0000000..a338b88
--- /dev/null
+++ b/Sesion-01/Ejemplo-03/README.md
@@ -0,0 +1,274 @@
+# Ejemplo 03: Acceder con número telefónico
+
+## Objetivo
+
+* Establecer el registro de una cuenta con número telefónico y la simulación del inicio de sesión con el mismo método.
+
+## Desarrollo
+
+Con las funciones de creación de usuarios y de inicio de sesión de Auth, ahora se simulará el método del número telefónico.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Antes de modificar el código deben generarse las huellas digitales de nuestro proyecto y activar API DeviceCheck. En **Google Cloud Console**, habilita la [API de Android DeviceCheck](https://console.cloud.google.com/apis/library/androidcheck.googleapis.com?authuser=0) en tu proyecto. Se usará la clave de API de Firebase predeterminada, y se debe tener acceso a la API de DeviceCheck. Esto se ejemplifica en la siguiente imagen.
+
+
+
+2. Después, en Android Studio hacemos clic en la siguiente ruta: *Build > Generate Signed Bundle or APK*. Ahí es necesario hacer clic en *Next*, como se visualiza en la siguiente imagen.
+
+
+
+3. Posteriormente, al ingresar datos de identidad se recomienda agregar la siguiente información, ya que esta llave sólo se usará para pruebas.
+
+ **Contraseña**: android
+
+ **Alias**: android
+
+ **Name**: debug
+
+
+
+4. Al estar creada la llave, esta tendrá el nombre de **debug.keystore.jks**. Se debe eliminar la extensión **.jks**, por lo que quedará del siguiente modo: **debug.keystore**, como se aprecia en la imagen siguiente.
+
+
+
+5. Después debe hacerse clic en la siguiente ruta: File > Project Structure > Modules > app > Signing Configs y una vez dentro es necesario buscar el archivo de la llave, agregar los datos de usuario y hacer clic en OK. Este proceso se representa en la siguiente imagen.
+
+
+
+6. Luego, en la pestaña de *Default Config*, en la opción de *Signing Config*, seleccionamos ***$signingConfigs.debug***. Después debe hacerse clic en OK, como se visualiza en la imagen.
+
+
+
+ Esto agrega la siguiente línea en el gradle
+
+ ```kotlin
+ signingConfigs {
+ debug {
+ storeFile file('/home/andres/Documentos/Android/DebugKey/debug.keystore')
+ storePassword 'android'
+ keyAlias 'android'
+ }
+ }
+ ```
+
+7. Así, para generar la huella ejecutamos la siguiente línea en la terminal.
+
+ ```hash
+ /opt/android-studio/jre/bin/keytool -list -v -keystore /home/andres/Documentos/Android/DebugKey/debug.keystore -alias android -storepass android -keypass android
+ ```
+
+ > Pro-tip: la primera parte es la ruta donde está instalado **keytool**, luego la ruta donde está la llave, y después los datos de ésta.
+
+ La salida esperada es:
+
+
+
+ > Pro-tip: guarda la clave SHA1 y SHA256.
+
+8. Ahora, configuraremos el método de acceso en Firebase Console. En el menú Authentication debe hacerse clic en la pestaña *Sign-in method* y habilitarse *Teléfono*.
+
+
+
+9. Debe hacerse clic para habilitar el check, como se visualiza en la imagen.
+
+
+
+ Este método requiere unos pasos extra de configuración, ya que la verificación trabaja de dos maneras. Estas formas se explicaron como último subtema en tu Prework.
+
+10. Es necesario agregar las huellas digitales de nuestra app. Para ello primero se debe dirigir hacia la configuración del proyecto en Firebase.
+
+
+
+ Al final de la configuración figura un botón para *Agregar las huellas*, como se aprecia en la imagen siguiente.
+
+
+
+11. Deben agregarse las dos huellas generadas, y el resultado debe ser el siguiente.
+
+
+
+12. Una vez configuradas las huellas es necesario dirigirse al código. Se modificará **PhoneActivity** de la siguiente manera.
+
+ ```kotlin
+ //Declaramos las variables
+ private lateinit var auth: FirebaseAuth
+
+ private var storedVerificationId: String? = ""
+ private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
+ private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
+ ```
+
+ ```kotlin
+ //Dentro de onCreate
+ auth = Firebase.auth
+ ```
+
+13. Después, en el clic del botón deben enviarse las variables declaradas, como se presenta a continuación.
+
+ ```kotlin
+ ...
+ resendVerificationCode(phone, resendToken)
+ ...
+ storedVerificationId?.let { it1 -> verifyPhoneNumberWithCode(it1, code) }
+ ...
+ ```
+14. Después se agrega el callback de *responses* de la siguiente forma.
+
+ ```kotlin
+ callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
+
+ override fun onVerificationCompleted(credential: PhoneAuthCredential) {
+ Log.d(TAG, "onVerificationCompleted:$credential")
+ signInWithPhoneAuthCredential(credential)
+ }
+
+ override fun onVerificationFailed(e: FirebaseException) {
+ Log.w(TAG, "onVerificationFailed", e)
+
+ binding.edtPhone.visibility = View.VISIBLE
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.loading.visibility = View.GONE
+
+ when (e) {
+ is FirebaseAuthInvalidCredentialsException -> {
+ // Invalid request
+ Utility.displaySnackBar(
+ binding.root,
+ "Invalid request",
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ is FirebaseTooManyRequestsException -> {
+ // The SMS quota for the project has been exceeded
+ Utility.displaySnackBar(
+ binding.root,
+ "The SMS quota for the project has been exceeded",
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ else -> {
+ Utility.displaySnackBar(
+ binding.root,
+ e.message.toString(),
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ }
+ }
+
+ override fun onCodeSent(
+ verificationId: String,
+ token: PhoneAuthProvider.ForceResendingToken
+ ) {
+ Log.d(TAG, "onCodeSent:$verificationId")
+
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.edtCode.visibility = View.VISIBLE
+ binding.loading.visibility = View.GONE
+
+ Utility.displaySnackBar(
+ binding.root,
+ "Code sent",
+ this@PhoneActivity,
+ R.color.green
+ )
+
+ storedVerificationId = verificationId
+ resendToken = token
+ }
+ }
+ ```
+
+15. Posteriormente se cambia el tipo de variable para token en la función *resendVerificationCode*, como en el siguiente código.
+
+ ```Kotlin
+ token: PhoneAuthProvider.ForceResendingToken?
+ ```
+
+16. Luego modificamos la función *startPhoneNumberVerification* con el siguiente código:
+
+ ```Kotlin
+ val options = PhoneAuthOptions.newBuilder(auth)
+ .setPhoneNumber(phoneNumber) // Phone number to verify
+ .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
+ .setActivity(this) // Activity (for callback binding)
+ .setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
+ .build()
+ PhoneAuthProvider.verifyPhoneNumber(options)
+ ```
+
+17. En este paso se agrega la siguiente función para validar las credenciales: **createAccount**, como de la siguiente forma.
+
+ ```kotlin
+ private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
+ auth.signInWithCredential(credential)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ // Sign in success, update UI with the signed-in user's information
+ Log.d(TAG, "signInWithCredential:success")
+
+ val user = task.result?.user
+ updateUI(user, null)
+ } else {
+ // Sign in failed, display a message and update the UI
+ Log.w(TAG, "signInWithCredential:failure", task.exception)
+ if (task.exception is FirebaseAuthInvalidCredentialsException) {
+ // The verification code entered was invalid
+
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.btnContinue.text = "Resend code"
+
+ Utility.displaySnackBar(
+ binding.root,
+ "The verification code entered was invalid",
+ this@PhoneActivity,
+ R.color.red
+ )
+ } else {
+ task.exception?.let { updateUI(null, it) }
+ }
+ // Update UI
+ }
+ }
+ }
+ ```
+
+18. Asimismo, en ambas respuestas, *(success - failure)*, llamamos a la función *updateUI*, la cual se encargará de mostrar los mensajes, así que la reemplazamos con el siguiente bloque de código.
+
+ ```kotlin
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ binding.edtPhone.visibility = View.VISIBLE
+ if (exception != null) {
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ Utility.displaySnackBar(binding.root, exception.message.toString(), this, R.color.red)
+ } else {
+ Utility.displaySnackBar(binding.root, "Login was successful", this, R.color.green)
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ }
+ }
+ ```
+
+19. Ahora debe ejecutarse la app con un número telefónico, como se aprecia en la imagen.
+
+
+
+20. La respuesta después de unos segundos debería ser la siguiente pantalla.
+
+
+
+ Además, si utilizaste tu número de teléfono deberías de recibir un mensaje de texto con el código.
+
+¡Felicidades! Ahora tu app puede enviar códigos de verificación.
+El siguiente reto te espera con el logro de validar el código y concluir el registro.
+
+
+
+
+[Siguiente ](../Reto-02/README.md)(Reto 2)
\ No newline at end of file
diff --git a/Sesion-01/Ejemplo-03/assets/01.png b/Sesion-01/Ejemplo-03/assets/01.png
new file mode 100644
index 0000000..d913f02
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/01.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/02.png b/Sesion-01/Ejemplo-03/assets/02.png
new file mode 100644
index 0000000..0dd4380
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/02.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/03.png b/Sesion-01/Ejemplo-03/assets/03.png
new file mode 100644
index 0000000..7772780
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/03.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/04.png b/Sesion-01/Ejemplo-03/assets/04.png
new file mode 100644
index 0000000..9bf41ab
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/04.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/05.png b/Sesion-01/Ejemplo-03/assets/05.png
new file mode 100644
index 0000000..ebe920f
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/05.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/06.png b/Sesion-01/Ejemplo-03/assets/06.png
new file mode 100644
index 0000000..12d47e7
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/06.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/07.png b/Sesion-01/Ejemplo-03/assets/07.png
new file mode 100644
index 0000000..66aa5eb
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/07.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/08.png b/Sesion-01/Ejemplo-03/assets/08.png
new file mode 100644
index 0000000..7355c4c
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/08.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/09.png b/Sesion-01/Ejemplo-03/assets/09.png
new file mode 100644
index 0000000..a085d46
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/09.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/10.png b/Sesion-01/Ejemplo-03/assets/10.png
new file mode 100644
index 0000000..b180d1b
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/10.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/11.png b/Sesion-01/Ejemplo-03/assets/11.png
new file mode 100644
index 0000000..a20e092
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/11.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/12.png b/Sesion-01/Ejemplo-03/assets/12.png
new file mode 100644
index 0000000..be6c11a
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/12.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/13.png b/Sesion-01/Ejemplo-03/assets/13.png
new file mode 100644
index 0000000..20bebf9
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/13.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/14.png b/Sesion-01/Ejemplo-03/assets/14.png
new file mode 100644
index 0000000..87f0439
Binary files /dev/null and b/Sesion-01/Ejemplo-03/assets/14.png differ
diff --git a/Sesion-01/Ejemplo-03/assets/README.md b/Sesion-01/Ejemplo-03/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-01/Ejemplo-03/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-01/Postwork/01.png b/Sesion-01/Postwork/01.png
new file mode 100644
index 0000000..47e51f2
Binary files /dev/null and b/Sesion-01/Postwork/01.png differ
diff --git a/Sesion-01/Postwork/02.png b/Sesion-01/Postwork/02.png
new file mode 100644
index 0000000..c2c0413
Binary files /dev/null and b/Sesion-01/Postwork/02.png differ
diff --git a/Sesion-01/Postwork/README.md b/Sesion-01/Postwork/README.md
new file mode 100644
index 0000000..7a2d79f
--- /dev/null
+++ b/Sesion-01/Postwork/README.md
@@ -0,0 +1,126 @@
+# Postwork 1 - Firebase Authentication - Simplifica el registro e inicio de sesión
+
+## Objetivo
+
+* Establecer el inicio de sesión en la app mediante una cuenta de Google.
+* Simular el inicio de sesión con el método de autenticación de la cuenta de Google.
+
+## Desarrollo
+
+En los ejemplos de esta sesión aprendimos a iniciar sesión y registrar usuarios sin agregar código del lado del servidor. Para el Postwork 01 queremos poner en práctica lo aprendido.
+
+El proyecto base tiene el botón de Google. Al hacer clic sobre él, este debe permitir iniciar sesión con algún correo de Google. Te recomendamos apoyarte con la documentación oficial.
+
+[Haz clic aquí para consultar la documentación.](https://firebase.google.com/docs/auth/android/google-signin)
+
+### Indicaciones generales:
+- Habilita el inicio por Google desde Firebase Console previo a la edición de código.
+- Establece la siguiente dependencia:
+*Implementation 'com.google.android.gms:play-services-auth:19.0.0'*
+Es posible hacer la implementación en el *MainActivity*
+- Al final ejecuta la app e inicia sesión con la cuenta de Google. Para concluir verifica que tu correo de login esté en el panel de usuarios en Firebase Console, como se aprecia en la siguiente imagen.
+
+#### A continuación se muestra una propuesta de flujo:
+
+
+
+
+
+
+
+
+
+ Solución
+
+ ```kotlin
+ // Variables
+ private lateinit var auth: FirebaseAuth
+
+ private lateinit var googleSignInClient: GoogleSignInClient
+ ```
+
+ ```kotlin
+ // Dentro de onCreate
+ FirebaseApp.initializeApp(this)
+
+ val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
+ .requestIdToken(getString(R.string.default_web_client_id))
+ .requestEmail()
+ .build()
+
+ googleSignInClient = GoogleSignIn.getClient(this, gso)
+
+ auth = Firebase.auth
+ ```
+
+ ```kotlin
+ // onClick btnGoogle
+ binding.btnGoogle.setOnClickListener {
+ val signInIntent = googleSignInClient.signInIntent
+ startActivityForResult(signInIntent, RC_SIGN_IN)
+ }
+ ```
+
+ ```kotlin
+ // Funciones nuevas
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
+ if (requestCode == RC_SIGN_IN) {
+ val task = GoogleSignIn.getSignedInAccountFromIntent(data)
+ try {
+ // Google Sign In was successful, authenticate with Firebase
+ val account = task.getResult(ApiException::class.java)!!
+ Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
+ firebaseAuthWithGoogle(account.idToken!!)
+ } catch (e: ApiException) {
+ // Google Sign In failed, update UI appropriately
+ Log.w(TAG, "Google sign in failed", e)
+ Utility.displaySnackBar(binding.root, "Google sign in failed", this, R.color.red)
+ }
+ }
+ }
+
+ private fun firebaseAuthWithGoogle(idToken: String) {
+ val credential = GoogleAuthProvider.getCredential(idToken, null)
+ auth.signInWithCredential(credential)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ // Sign in success, update UI with the signed-in user's information
+ Log.d(TAG, "signInWithCredential:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ // If sign in fails, display a message to the user.
+ Log.w(TAG, "signInWithCredential:failure", task.exception)
+ updateUI(null, task.exception)
+ }
+ }
+ }
+
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ binding.btnGoogle.visibility = View.VISIBLE
+ if (exception != null) {
+ binding.loading.visibility = View.GONE
+ binding.btnGoogle.visibility = View.VISIBLE
+ Utility.displaySnackBar(binding.root, exception.message.toString(), this, R.color.red)
+ } else {
+ Utility.displaySnackBar(binding.root, "Login was successful: ", this, R.color.green)
+ binding.loading.visibility = View.GONE
+ binding.btnGoogle.visibility = View.VISIBLE
+ }
+ }
+ ```
+
+ Ejecuta la app e inicia con Google, al final deberías de ver tu correo en el panel de usuarios en Firebase Console
+
+
+
+
+
+
+[Regresar ](../README.md)(Sesión 01)
+
+[Siguiente ](../../Sesion-02/README.md)(Sesión 02)
+
diff --git a/Sesion-01/README.md b/Sesion-01/README.md
new file mode 100644
index 0000000..6f65c5f
--- /dev/null
+++ b/Sesion-01/README.md
@@ -0,0 +1,65 @@
+
+# :wave: Sesión 01: Firebase Authentication - Simplifica el inicio de sesión y el registro
+
+## 🎯 Objetivo de la sesión:
+Implementar Firebase Authentication en el código de la app para operar el registro e inicio de sesión con los métodos de Firebase.
+
+## 🎯 Qué aprenderán
+
+- Implementación de firebase-auth en un proyecto.
+- Gestión de usuarios sin código en el servidor.
+- Simulación de registro y login con diferentes métodos de autenticación de Auth.
+
+## ⚙ Requisitos
+
++ Revisión previa del prework de esta sesión
++ Cuenta de Google
++ Proyecto de Firebase
++ Android studio
+
+## 🎩 Desarrollo
+
+En esta sesión aprenderemos cuáles son los servicios de Firebase, las funciones que suma Authentication, y cómo se implementa dentro de un proyecto de Android para un registro e inicio de sesión enlazados con Auth, como la llamaremos también.
+Asimismo, se operará la app para verificar la funcionalidad del registro y del login mediante SMS,, correo y cuenta de Google.
+
+Firebase Authentication proporciona servicios de backend, SDK y bibliotecas de IU preelaboradas que sirven para autenticar a los usuarios en tu app. Así, es posible la autenticación mediante contraseñas, números de teléfono, proveedores de identidad federada populares, como Google, Facebook y Twitter, y muchos más.
+
+
+## ⚙ Configuración
+
+### Firebase - Setup inicial
+
+Antes de implementar firebase en nuestra app, debemos configurar un proyecto en la Firebase console. Para ello deben realizarse los siguientes pasos:
+
+1. Abrir Firebase Console mediante una cuenta google que poseamos.
+2. Crear un proyecto nuevo.
+
+
+
+3. Asignar un nombre al proyecto. En este caso se le llamará "Bedu".
+4. Aceptar la habilitación de Google Analytics para el proyecto.
+
+
+
+5. Seleccionar México como ubicación Analytics, hacer clic en los recuadros para aceptar todos los términos, y finalmente hacer clic en Crear proyecto.
+
+
+
+Y listo, ya creamos nuestro Firebase Project.
+
+
+
+
+
+## 📂 Organización de la clase
+
+- [Ejemplo 01: Implementar Firebase Authentication](./Ejemplo-01/README.md)
+- [Ejemplo 02: Registrarse con correo y contraseña](./Ejemplo-02/README.md)
+ - [Reto 01: Iniciar sesión](./Reto-01/README.md)
+- [Ejemplo 03: Accede con número telefónico](./Ejemplo-03/README.md)
+ - [Reto 02: Verificar y reenviar código](./Reto-02/README.md)
+- [Postwork: Accede con Google](./Postwork/README.md)
+
+
+
+
diff --git a/Sesion-01/Reto-01/README.md b/Sesion-01/Reto-01/README.md
new file mode 100644
index 0000000..dd50b3f
--- /dev/null
+++ b/Sesion-01/Reto-01/README.md
@@ -0,0 +1,53 @@
+# Reto 01: Iniciar sesión
+
+## Objetivo
+
+* Implementar el inicio de sesión en el proyecto Android y simularlo con respuestas de mensajes de registro no encontrado, contraseña errónea y bienvenido.
+
+## Desarrollo
+
+En el ejemplo 2 se agregó la función para crear usuarios, por lo que ahora se implementará el inicio de sesión y se simulará con todos los escenarios de respuesta.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Agregar inicio de sesión con Auth. Para ello ve a la clase EmailActivity y modifica la función signIn. El código es muy similar a la función createAccount, debe cambiarse de *createUserWithEmailAndPassword* a *signInWithEmailAndPassword*.
+
+Los resultados esperados deben ser similares a los de las siguientes imágenes.
+
+
+
+
+
+
+
+
+
+
+
+ Solución
+
+```kotlin
+private fun signIn(email: String, password: String) {
+ auth.signInWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ Log.d(TAG, "signInWithEmail:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ Log.w(TAG, "signInWithEmail:failure", task.exception)
+ task.exception?.let { updateUI(null, it) }
+ }
+ }
+}
+```
+
+
+
+
+> Las llamadas a Firebase retornan excepciones, y por eso no fue necesario agregar los mensajes de manera manual **task.exception**.
+
+
+
+
+[Siguiente ](../Ejemplo-03/README.md)(Ejemplo 3)
\ No newline at end of file
diff --git a/Sesion-01/Reto-01/assets/01.png b/Sesion-01/Reto-01/assets/01.png
new file mode 100644
index 0000000..7f60345
Binary files /dev/null and b/Sesion-01/Reto-01/assets/01.png differ
diff --git a/Sesion-01/Reto-01/assets/02.png b/Sesion-01/Reto-01/assets/02.png
new file mode 100644
index 0000000..79c2713
Binary files /dev/null and b/Sesion-01/Reto-01/assets/02.png differ
diff --git a/Sesion-01/Reto-01/assets/03.png b/Sesion-01/Reto-01/assets/03.png
new file mode 100644
index 0000000..95f325b
Binary files /dev/null and b/Sesion-01/Reto-01/assets/03.png differ
diff --git a/Sesion-01/Reto-01/assets/README.md b/Sesion-01/Reto-01/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-01/Reto-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-01/Reto-02/README.md b/Sesion-01/Reto-02/README.md
new file mode 100644
index 0000000..e5d84a3
--- /dev/null
+++ b/Sesion-01/Reto-02/README.md
@@ -0,0 +1,84 @@
+# Reto 02: Verificar y reenviar código
+
+## Objetivo
+
+* Operar el registro de una cuenta con número telefónico y la simulación del inicio de sesión con el mismo método mediante la validación del código de Auth y/o con la solicitud de un código nuevo.
+
+## Desarrollo
+
+En el ejemplo 3 solicitamos el código para registrar un usuario con el número telefónico y ahora se concluirá el registro de manera satisfactoria y se simulará este método.
+Para hacerlo realiza los siguientes pasos:
+
+1. Crear PhoneAuthProvider con el código de verificación y el code que se recibió vía SMS. Después solicitar la comprobación con la función **signInWithPhoneAuthCredential**, y el resto lo hará *updateUI*.
+
+ > Para ello se debe crear Provider > PhoneAuthProvider.getCredential(verificationId, userCode)
+
+ Los resultados esperados deben ser similares a los siguientes:
+
+
+
+
+
+
+
+
+ Solución
+
+ ```kotlin
+ private fun verifyPhoneNumberWithCode(verificationId: String, code: String) {
+ val credential = PhoneAuthProvider.getCredential(verificationId, code)
+ signInWithPhoneAuthCredential(credential)
+ }
+ ```
+
+
+
+
+
+
+2. Si el código expiró o está mal escrito es necesario agregar una acción al botón actual para solicitar un nuevo código. para ello se debe agregar la petición en la función **resendVerificationCode**.
+
+ > Pro-tip: Esta llamada es muy similar a **startPhoneNumberVerification**.
+
+ Los resultados esperados deben ser similares a los siguientes:
+
+
+
+
+
+
+
+
+
+
+ Solución
+
+ ```kotlin
+ private fun resendVerificationCode(
+ phoneNumber: String,
+ token: PhoneAuthProvider.ForceResendingToken?
+ ) {
+ val optionsBuilder = PhoneAuthOptions.newBuilder(auth)
+ .setPhoneNumber(phoneNumber) // Phone number to verify
+ .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
+ .setActivity(this) // Activity (for callback binding)
+ .setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
+ if (token != null) {
+ optionsBuilder.setForceResendingToken(token) // callback's ForceResendingToken
+ }
+ PhoneAuthProvider.verifyPhoneNumber(optionsBuilder.build())
+ }
+ ```
+
+
+
+
+3. El último paso es la comprobación de que el registro fue correcto, como se aprecia en la siguiente imagen.
+
+
+
+
+
+
+[Siguiente ](../Postwork/README.md)(Postwork)
+
diff --git a/Sesion-01/Reto-02/assets/01.png b/Sesion-01/Reto-02/assets/01.png
new file mode 100644
index 0000000..6ce3384
Binary files /dev/null and b/Sesion-01/Reto-02/assets/01.png differ
diff --git a/Sesion-01/Reto-02/assets/02.png b/Sesion-01/Reto-02/assets/02.png
new file mode 100644
index 0000000..78e9f4e
Binary files /dev/null and b/Sesion-01/Reto-02/assets/02.png differ
diff --git a/Sesion-01/Reto-02/assets/03.png b/Sesion-01/Reto-02/assets/03.png
new file mode 100644
index 0000000..2f33fd2
Binary files /dev/null and b/Sesion-01/Reto-02/assets/03.png differ
diff --git a/Sesion-01/Reto-02/assets/04.png b/Sesion-01/Reto-02/assets/04.png
new file mode 100644
index 0000000..0e6f0fc
Binary files /dev/null and b/Sesion-01/Reto-02/assets/04.png differ
diff --git a/Sesion-01/Reto-02/assets/05.png b/Sesion-01/Reto-02/assets/05.png
new file mode 100644
index 0000000..c172218
Binary files /dev/null and b/Sesion-01/Reto-02/assets/05.png differ
diff --git a/Sesion-01/Reto-02/assets/README.md b/Sesion-01/Reto-02/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-01/Reto-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-01/images/01.png b/Sesion-01/images/01.png
new file mode 100644
index 0000000..8871e21
Binary files /dev/null and b/Sesion-01/images/01.png differ
diff --git a/Sesion-01/images/02.png b/Sesion-01/images/02.png
new file mode 100644
index 0000000..7374183
Binary files /dev/null and b/Sesion-01/images/02.png differ
diff --git a/Sesion-01/images/03.png b/Sesion-01/images/03.png
new file mode 100644
index 0000000..8473c8a
Binary files /dev/null and b/Sesion-01/images/03.png differ
diff --git a/Sesion-01/images/04.png b/Sesion-01/images/04.png
new file mode 100644
index 0000000..ba47f11
Binary files /dev/null and b/Sesion-01/images/04.png differ
diff --git a/Sesion-02/Ejemplo-01/README.md b/Sesion-02/Ejemplo-01/README.md
new file mode 100644
index 0000000..932afa1
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/README.md
@@ -0,0 +1,48 @@
+# Ejemplo 01: Implementar Firebase Crashlytics
+
+## Objetivo
+
+* Implementar y configurar Firebase Crashlytics en un proyecto base.
+
+## Desarrollo
+
+A partir de un proyecto de Android previamente creado se implementará el BaaS de Firebase Crashlytics para integrar sus servicios de gestión de errores.
+
+Usaremos el [Proyecto base](./base) y le modificaremos lo que se requiera. Para hacerlo realiza los siguientes pasos:
+
+1. Ejecutamos el proyecto base con Android Studio. Este desplegará la siguiente interfaz.
+
+
+
+2. Ahora, agregaremos las librerías de Firebase. Para ello hacemos clic en la siguiente ruta: *Tools > Firebase*.
+
+
+
+3. El resultado será la siguiente ventana. Es necesario identificar la opción de Crashlytics, hacer clic en ella, y después hacer clic en la primer opción, enlistada como *Get started with Firebase Crashlytics*.
+
+
+
+ El proyecto debería estar conectado, ya que fue utilizado con firebase en la sesión anterior.
+ Nota: Si el proyecto no está conectado es necesario dirigirse al Ejemplo 1 del Work 1. Ahí se explica cómo conectarlo.
+
+ [Haz clic aquí para consultar el Ejemplo 1 del Work 1](https://github.com/beduExpert/Android-Avanzado-2021/tree/main/Sesion-01/Ejemplo-01)
+
+4. Ahora debe ejecutarse el paso 2 *Add Crashlytics SDK to your app*, como se aprecia en la imagen.
+
+
+
+ Esta acción agrega *crashlytics y analytics* al gradle.
+
+5. Posteriormente, es necesario hacer clic en el botón de aceptar los cambios.
+
+
+
+6. Ahora debemos dirigirnos a Firebase Console y habilitar *Crashlytics*, como se visualiza en la siguiente imagen.
+
+
+
+¡Felicidades! Ya implementaste Firebase Crashlytics en tu proyecto Android.
+
+
+
+[Siguiente ](../Ejemplo-02/README.md)(Ejemplo 2)
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/assets/01.png b/Sesion-02/Ejemplo-01/assets/01.png
new file mode 100644
index 0000000..9f004cf
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/01.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/02.png b/Sesion-02/Ejemplo-01/assets/02.png
new file mode 100644
index 0000000..8e48756
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/02.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/03.png b/Sesion-02/Ejemplo-01/assets/03.png
new file mode 100644
index 0000000..af6f959
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/03.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/04.png b/Sesion-02/Ejemplo-01/assets/04.png
new file mode 100644
index 0000000..ba7abbc
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/04.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/05.png b/Sesion-02/Ejemplo-01/assets/05.png
new file mode 100644
index 0000000..6ce09bd
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/05.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/06.png b/Sesion-02/Ejemplo-01/assets/06.png
new file mode 100644
index 0000000..8b81f39
Binary files /dev/null and b/Sesion-02/Ejemplo-01/assets/06.png differ
diff --git a/Sesion-02/Ejemplo-01/assets/README.md b/Sesion-02/Ejemplo-01/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/.gitignore b/Sesion-02/Ejemplo-01/base/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/Sesion-02/Ejemplo-01/base/app/.gitignore b/Sesion-02/Ejemplo-01/base/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/build.gradle b/Sesion-02/Ejemplo-01/base/app/build.gradle
new file mode 100644
index 0000000..99d653d
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/build.gradle
@@ -0,0 +1,64 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'com.google.gms.google-services'
+}
+
+android {
+ signingConfigs {
+ debug {
+ storeFile file('/home/andres/Documentos/Android/DebugKey/debug.keystore')
+ storePassword 'android'
+ keyAlias 'android'
+ }
+ }
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ applicationId "com.bedu.auth"
+ minSdkVersion 19
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ signingConfig signingConfigs.debug
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ buildFeatures {
+ viewBinding true
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'com.google.android.material:material:1.3.0'
+
+ implementation platform('com.google.firebase:firebase-bom:28.0.1')
+ implementation 'com.google.firebase:firebase-auth-ktx'
+
+ implementation 'com.google.firebase:firebase-auth:21.0.1'
+
+ implementation 'com.google.android.gms:play-services-auth:19.0.0'
+
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/google-services.json b/Sesion-02/Ejemplo-01/base/app/google-services.json
new file mode 100644
index 0000000..30be9fc
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/google-services.json
@@ -0,0 +1,39 @@
+{
+ "project_info": {
+ "project_number": "636305410157",
+ "project_id": "bedu-5b491",
+ "storage_bucket": "bedu-5b491.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:636305410157:android:47a99d8f03964e99455764",
+ "android_client_info": {
+ "package_name": "com.bedu.auth"
+ }
+ },
+ "oauth_client": [
+ {
+ "client_id": "636305410157-ds51vlvmpban3jmqsguf4i41idvh5984.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyA_gWTzmEs5gB-eiOmpC2ZTjFmTiXoMWlA"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": [
+ {
+ "client_id": "636305410157-ds51vlvmpban3jmqsguf4i41idvh5984.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/proguard-rules.pro b/Sesion-02/Ejemplo-01/base/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt b/Sesion-02/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..b5e9233
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/androidTest/java/com/bedu/auth/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.bedu.auth
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.bedu.auth", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/AndroidManifest.xml b/Sesion-02/Ejemplo-01/base/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..10c2861
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt
new file mode 100644
index 0000000..40146eb
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/utils/Utility.kt
@@ -0,0 +1,33 @@
+package com.bedu.auth.utils
+
+import android.content.Context
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorRes
+import androidx.core.content.ContextCompat
+import com.bedu.auth.R
+import com.google.android.material.snackbar.Snackbar
+
+object Utility {
+
+ //display SnackBar
+ fun displaySnackBar(view: View, s: String, context: Context, @ColorRes colorRes: Int) {
+
+ Snackbar.make(view, s, Snackbar.LENGTH_LONG)
+ .withColor(ContextCompat.getColor(context, colorRes))
+ .setTextColor(ContextCompat.getColor(context, R.color.white))
+ .show()
+
+ }
+
+ fun View.hideKeyboard() {
+ val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputManager.hideSoftInputFromWindow(windowToken, 0)
+ }
+
+ private fun Snackbar.withColor(@ColorInt colorInt: Int): Snackbar {
+ this.view.setBackgroundColor(colorInt)
+ return this
+ }
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt
new file mode 100644
index 0000000..4771758
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/EmailActivity.kt
@@ -0,0 +1,130 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import android.widget.Toast
+import androidx.core.widget.doAfterTextChanged
+import com.bedu.auth.R
+import com.bedu.auth.databinding.ActivityEmailBinding
+import com.bedu.auth.utils.Utility
+import com.bedu.auth.utils.Utility.hideKeyboard
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.auth.FirebaseUser
+import com.google.firebase.auth.ktx.auth
+import com.google.firebase.ktx.Firebase
+import java.lang.Exception
+
+class EmailActivity : Activity() {
+
+ private lateinit var binding: ActivityEmailBinding
+
+ private lateinit var auth: FirebaseAuth
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityEmailBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ auth = Firebase.auth
+
+ handleClick()
+ }
+
+ private fun handleClick() {
+
+ binding.btnLogin.setOnClickListener {
+ it.hideKeyboard()
+
+ binding.btnLogin.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ signIn(email, password)
+ }
+ binding.btnRegister.setOnClickListener {
+ it.hideKeyboard()
+
+ binding.btnLogin.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ createAccount(email, password)
+ }
+
+ binding.editText.doAfterTextChanged {
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ binding.btnLogin.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ binding.btnRegister.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ }
+
+ binding.editText2.doAfterTextChanged {
+ val email = binding.editText.text.toString()
+ val password = binding.editText2.text.toString()
+
+ binding.btnLogin.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ binding.btnRegister.isEnabled = email.isNotEmpty() && password.isNotEmpty()
+ }
+ }
+
+ private fun createAccount(email: String, password: String) {
+ auth.createUserWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ Log.d(TAG, "createUserWithEmail:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ Log.w(TAG, "createUserWithEmail:failure", task.exception)
+ updateUI(null, task.exception)
+ }
+ }
+ }
+
+ private fun signIn(email: String, password: String) {
+ auth.signInWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ Log.d(TAG, "signInWithEmail:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ Log.w(TAG, "signInWithEmail:failure", task.exception)
+ task.exception?.let { updateUI(null, it) }
+ }
+ }
+ }
+
+ private fun sendEmailVerification() {
+ }
+
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ if (exception != null) {
+ binding.loading.visibility = View.GONE
+ binding.btnLogin.visibility = View.VISIBLE
+ Utility.displaySnackBar(binding.root, exception.message.toString(), this, R.color.red)
+ } else {
+ Utility.displaySnackBar(binding.root, "Login was successful", this, R.color.green)
+ binding.loading.visibility = View.GONE
+ binding.btnLogin.visibility = View.VISIBLE
+ }
+ }
+
+ private fun reload() {
+
+ }
+
+ companion object {
+ private const val TAG = "EmailPassword"
+ }
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt
new file mode 100644
index 0000000..fa8236a
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/MainActivity.kt
@@ -0,0 +1,103 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.widget.Toast
+import com.bedu.auth.R
+import com.bedu.auth.databinding.ActivityOptionsBinding
+import com.bedu.auth.utils.Utility
+import com.google.android.gms.auth.api.signin.GoogleSignIn
+import com.google.android.gms.auth.api.signin.GoogleSignInClient
+import com.google.android.gms.auth.api.signin.GoogleSignInOptions
+import com.google.android.gms.common.api.ApiException
+import com.google.firebase.FirebaseApp
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.auth.FirebaseUser
+import com.google.firebase.auth.GoogleAuthProvider
+import com.google.firebase.auth.ktx.auth
+import com.google.firebase.ktx.Firebase
+
+class MainActivity : Activity() {
+
+ private lateinit var binding: ActivityOptionsBinding
+
+ private lateinit var auth: FirebaseAuth
+
+ private lateinit var googleSignInClient: GoogleSignInClient
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityOptionsBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ FirebaseApp.initializeApp(this)
+
+ val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
+ .requestIdToken(getString(R.string.default_web_client_id))
+ .requestEmail()
+ .build()
+
+ googleSignInClient = GoogleSignIn.getClient(this, gso)
+
+ auth = Firebase.auth
+
+ handleClick()
+ }
+
+ private fun handleClick() {
+
+ binding.btnCrash.setOnClickListener {
+ Toast.makeText(this, "Crash", Toast.LENGTH_SHORT).show()
+ }
+ binding.btnSetInfo.setOnClickListener {
+ Toast.makeText(this, "SetInfo", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == RC_SIGN_IN) {
+ val task = GoogleSignIn.getSignedInAccountFromIntent(data)
+ try {
+ // Google Sign In was successful, authenticate with Firebase
+ val account = task.getResult(ApiException::class.java)!!
+ Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
+ firebaseAuthWithGoogle(account.idToken!!)
+ } catch (e: ApiException) {
+ Log.w(TAG, "Google sign in failed", e)
+ Utility.displaySnackBar(binding.root, "Google sign in failed", this, R.color.red)
+ }
+ }
+ }
+
+ private fun firebaseAuthWithGoogle(idToken: String) {
+ val credential = GoogleAuthProvider.getCredential(idToken, null)
+ auth.signInWithCredential(credential)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ // Sign in success, update UI with the signed-in user's information
+ Log.d(TAG, "signInWithCredential:success")
+ val user = auth.currentUser
+ updateUI(user, null)
+ } else {
+ // If sign in fails, display a message to the user.
+ Log.w(TAG, "signInWithCredential:failure", task.exception)
+ updateUI(null, task.exception)
+ }
+ }
+ }
+
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ }
+
+ companion object {
+ private const val TAG = "GoogleActivity"
+ private const val RC_SIGN_IN = 9001
+ }
+
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt
new file mode 100644
index 0000000..a0802ce
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/java/com/bedu/auth/view/PhoneActivity.kt
@@ -0,0 +1,227 @@
+package com.bedu.auth.view
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import androidx.core.widget.doAfterTextChanged
+import com.bedu.auth.R
+import com.bedu.auth.databinding.ActivityPhoneBinding
+import com.bedu.auth.utils.Utility
+import com.bedu.auth.utils.Utility.hideKeyboard
+import com.google.firebase.FirebaseException
+import com.google.firebase.FirebaseTooManyRequestsException
+import com.google.firebase.auth.*
+import com.google.firebase.auth.ktx.auth
+import com.google.firebase.ktx.Firebase
+import java.util.concurrent.TimeUnit
+
+
+class PhoneActivity : Activity() {
+
+ private lateinit var binding: ActivityPhoneBinding
+
+ //Declaramos las variables
+ private lateinit var auth: FirebaseAuth
+
+ private var storedVerificationId: String? = ""
+ private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
+ private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityPhoneBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ auth = Firebase.auth
+
+ binding.btnContinue.setOnClickListener {
+ it.hideKeyboard()
+
+ val phone = binding.edtPhone.text.toString()
+
+ when {
+ binding.btnContinue.text == "Resend code" -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtCode.text.clear()
+ resendVerificationCode(phone, resendToken)
+ binding.btnContinue.text = "Continue"
+ }
+ binding.edtPhone.visibility == View.VISIBLE -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtPhone.visibility = View.INVISIBLE
+
+ startPhoneNumberVerification(phone)
+ }
+ binding.edtCode.text.isNotEmpty() -> {
+ binding.btnContinue.visibility = View.GONE
+ binding.loading.visibility = View.VISIBLE
+ binding.edtCode.visibility = View.GONE
+
+ val code = binding.edtCode.text.toString()
+
+ storedVerificationId?.let { it1 -> verifyPhoneNumberWithCode(it1, code) }
+ }
+ }
+ }
+
+ binding.edtPhone.doAfterTextChanged {
+ val phone = binding.edtPhone.text.toString()
+
+ binding.btnContinue.isEnabled = phone.isNotEmpty()
+ }
+
+ callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
+
+ override fun onVerificationCompleted(credential: PhoneAuthCredential) {
+ Log.d(TAG, "onVerificationCompleted:$credential")
+ signInWithPhoneAuthCredential(credential)
+ }
+
+ override fun onVerificationFailed(e: FirebaseException) {
+ Log.w(TAG, "onVerificationFailed", e)
+
+ binding.edtPhone.visibility = View.VISIBLE
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.loading.visibility = View.GONE
+
+ when (e) {
+ is FirebaseAuthInvalidCredentialsException -> {
+ // Invalid request
+ Utility.displaySnackBar(
+ binding.root,
+ "Invalid request",
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ is FirebaseTooManyRequestsException -> {
+ // The SMS quota for the project has been exceeded
+ Utility.displaySnackBar(
+ binding.root,
+ "The SMS quota for the project has been exceeded",
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ else -> {
+ Utility.displaySnackBar(
+ binding.root,
+ e.message.toString(),
+ this@PhoneActivity,
+ R.color.red
+ )
+ }
+ }
+ }
+
+ override fun onCodeSent(
+ verificationId: String,
+ token: PhoneAuthProvider.ForceResendingToken
+ ) {
+ Log.d(TAG, "onCodeSent:$verificationId")
+
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.edtCode.visibility = View.VISIBLE
+ binding.loading.visibility = View.GONE
+
+ Utility.displaySnackBar(
+ binding.root,
+ "Code sent",
+ this@PhoneActivity,
+ R.color.green
+ )
+
+ storedVerificationId = verificationId
+ resendToken = token
+ }
+ }
+ }
+
+ private fun startPhoneNumberVerification(phoneNumber: String) {
+ val options = PhoneAuthOptions.newBuilder(auth)
+ .setPhoneNumber(phoneNumber) // Phone number to verify
+ .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
+ .setActivity(this) // Activity (for callback binding)
+ .setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
+ .build()
+ PhoneAuthProvider.verifyPhoneNumber(options)
+ }
+
+ private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
+ auth.signInWithCredential(credential)
+ .addOnCompleteListener(this) { task ->
+ if (task.isSuccessful) {
+ // Sign in success, update UI with the signed-in user's information
+ Log.d(TAG, "signInWithCredential:success")
+
+ val user = task.result?.user
+ updateUI(user, null)
+ } else {
+ // Sign in failed, display a message and update the UI
+ Log.w(TAG, "signInWithCredential:failure", task.exception)
+ if (task.exception is FirebaseAuthInvalidCredentialsException) {
+ // The verification code entered was invalid
+
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ binding.btnContinue.text = "Resend code"
+
+ Utility.displaySnackBar(
+ binding.root,
+ "The verification code entered was invalid",
+ this@PhoneActivity,
+ R.color.red
+ )
+ } else {
+ task.exception?.let { updateUI(null, it) }
+ }
+ // Update UI
+ }
+ }
+ }
+
+ private fun verifyPhoneNumberWithCode(verificationId: String, code: String) {
+ val credential = PhoneAuthProvider.getCredential(verificationId, code)
+ signInWithPhoneAuthCredential(credential)
+ }
+
+ private fun resendVerificationCode(
+ phoneNumber: String,
+ token: PhoneAuthProvider.ForceResendingToken?
+ ) {
+ val optionsBuilder = PhoneAuthOptions.newBuilder(auth)
+ .setPhoneNumber(phoneNumber) // Phone number to verify
+ .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
+ .setActivity(this) // Activity (for callback binding)
+ .setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
+ if (token != null) {
+ optionsBuilder.setForceResendingToken(token) // callback's ForceResendingToken
+ }
+ PhoneAuthProvider.verifyPhoneNumber(optionsBuilder.build())
+ }
+ // [END resend_verification]
+
+ private fun updateUI(user: FirebaseUser?, exception: Exception?) {
+ binding.edtPhone.visibility = View.VISIBLE
+ if (exception != null) {
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ Utility.displaySnackBar(binding.root, exception.message.toString(), this, R.color.red)
+ } else {
+ Utility.displaySnackBar(binding.root, "Login was successful", this, R.color.green)
+ binding.loading.visibility = View.GONE
+ binding.btnContinue.visibility = View.VISIBLE
+ }
+ }
+
+ companion object {
+ private const val TAG = "PhoneAuthActivity"
+ }
+
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml
new file mode 100644
index 0000000..c6c847c
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_email.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml
new file mode 100644
index 0000000..dee5010
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_options.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml
new file mode 100644
index 0000000..797bc91
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/layout/activity_phone.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/values-night/themes.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..81fd680
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/values/colors.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..38b0699
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/colors.xml
@@ -0,0 +1,13 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
+ #c90606
+ #008000
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/values/strings.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b6cfb0f
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Auth
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/main/res/values/themes.xml b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..72400e8
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt b/Sesion-02/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt
new file mode 100644
index 0000000..3cbca35
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/app/src/test/java/com/bedu/auth/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.bedu.auth
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/build.gradle b/Sesion-02/Ejemplo-01/base/build.gradle
new file mode 100644
index 0000000..9105b4b
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ext.kotlin_version = "1.5.10"
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.google.gms:google-services:4.3.8'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/gradle.properties b/Sesion-02/Ejemplo-01/base/gradle.properties
new file mode 100644
index 0000000..2521752
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# 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
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar b/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties b/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..47e2a92
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat Jun 05 12:34:09 CDT 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/Sesion-02/Ejemplo-01/base/gradlew b/Sesion-02/Ejemplo-01/base/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/Sesion-02/Ejemplo-01/base/gradlew.bat b/Sesion-02/Ejemplo-01/base/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Sesion-02/Ejemplo-01/base/settings.gradle b/Sesion-02/Ejemplo-01/base/settings.gradle
new file mode 100644
index 0000000..ac84e05
--- /dev/null
+++ b/Sesion-02/Ejemplo-01/base/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "Auth"
+include ':app'
diff --git a/Sesion-02/Ejemplo-02/README.md b/Sesion-02/Ejemplo-02/README.md
new file mode 100644
index 0000000..76be0ef
--- /dev/null
+++ b/Sesion-02/Ejemplo-02/README.md
@@ -0,0 +1,41 @@
+# Ejemplo 02: Provocar un error controlado
+
+## Objetivo
+
+- Producir un error en la app Android.
+- Enviar el error generado en la Firebase Console Crashlytics.
+
+## Desarrollo
+
+A partir del proyecto de Android previamente creado se producirá un error desde un botón, provocando el cierre inesperado de la app para consultarlo en Crashlytics.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. El asistente de Firebase en Android Studio importó la dependencia de analytics. Esta dependencia está en JAVA, y es posible trabajar con ella gracias a la interoperabilidad entre Java y Kotlin, pero Analytics está disponible en Kotlin, así que se recomienda implementarla en dicho lenguaje. Para ello es necesario entrar al Gradle, comentar la de JAVA y agregar la de Kotlin. El resultado debe ser el apreciado en la siguiente imagen.
+
+
+
+ ```kotlin
+ // implementation 'com.google.firebase:firebase-analytics:19.0.0'
+ implementation 'com.google.firebase:firebase-analytics-ktx'
+ ```
+2. Dentro del código debe abrirse la clase MainActivity del proyecto base, y debe agregarse el crash dentro del evento del botón btnCrash, como se observa en la siguiente imagen.
+
+
+
+ ```kotlin
+ binding.btnCrash.setOnClickListener {
+ throw RuntimeException("Test Crash") // Force a crash
+ }
+ ```
+
+3. Posteriormente, ejecutamos el proyecto y hacemos clic en el botón CRASH.
+
+
+
+ El resultado será un cierre inesperado de la app.
+
+
+
+
+[Siguiente ](../Reto-01/README.md)(Reto 1)
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-02/assets/01.png b/Sesion-02/Ejemplo-02/assets/01.png
new file mode 100644
index 0000000..a123532
Binary files /dev/null and b/Sesion-02/Ejemplo-02/assets/01.png differ
diff --git a/Sesion-02/Ejemplo-02/assets/02.png b/Sesion-02/Ejemplo-02/assets/02.png
new file mode 100644
index 0000000..b119c3f
Binary files /dev/null and b/Sesion-02/Ejemplo-02/assets/02.png differ
diff --git a/Sesion-02/Ejemplo-02/assets/03.png b/Sesion-02/Ejemplo-02/assets/03.png
new file mode 100644
index 0000000..50afbd7
Binary files /dev/null and b/Sesion-02/Ejemplo-02/assets/03.png differ
diff --git a/Sesion-02/Ejemplo-02/assets/README.md b/Sesion-02/Ejemplo-02/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-02/Ejemplo-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-03/README.md b/Sesion-02/Ejemplo-03/README.md
new file mode 100644
index 0000000..d096aa7
--- /dev/null
+++ b/Sesion-02/Ejemplo-03/README.md
@@ -0,0 +1,83 @@
+# Ejemplo 03: Funciones avanzadas
+
+## Objetivo
+
+- Implementar customKeys, envío de más información de errores controlados y registro de información de usuario para la gestión de errores en Crashlytics.
+
+## Desarrollo
+
+Ahora agregaremos más información a Crashlytics para tener más datos que ayuden a resolver los casos de errores mediante la gestión de bugs.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Las customKeys son variables que podemos enviar a Crashlytics para saber qué datos estaban cargados antes del error. Por ejemplo: si el crash fue provocado en el carrito de compra, es posible asignar los productos y cantidades que tenía agregadas.
+
+ El primer paso en enviar customKeys. Nuestra app tiene un segundo botón que dice SET INFO; este se encargará de agregar la información. Para ello debe agregarse el siguiente código dentro del setOnClickListener:
+
+ ```kotlin
+ // Set a key to a string.
+ FirebaseCrashlytics.getInstance().setCustomKey("str_key", "hello")
+
+ // Set a key to a boolean.
+ FirebaseCrashlytics.getInstance().setCustomKey("bool_key", true)
+
+ // Set a key to an int.
+ FirebaseCrashlytics.getInstance().setCustomKey("int_key", 1)
+
+ // Set a key to an long.
+ FirebaseCrashlytics.getInstance().setCustomKey("int_key", 1L)
+
+ // Set a key to a float.
+ FirebaseCrashlytics.getInstance().setCustomKey("float_key", 1.0f)
+
+ // Set a key to a double.
+ FirebaseCrashlytics.getInstance().setCustomKey("double_key", 1.0)
+ ```
+
+2. Posteriormente compilamos la app y hacemos clic en SET INFO, y después en CRASH. La aplicación se detendrá.
+
+3. Ahora es necesario dirigirse a Firebase Console Crashlytics y revisar el error. Este debería tener las customKeys en la pestaña de claves, como se aprecia en la siguiente imagen.
+
+
+
+4. Hay otra forma de agregar los customKeys que permite agregarlas todas juntas. La diferencia con la expuesta en el paso 1 es que en dicho proceso debe agregarse una por una. Para enviarlas en una sola llamada agregamos el siguiente código en el mismo botón de setOnClickListener.
+
+ ```kotlin
+ FirebaseCrashlytics.getInstance().setCustomKeys(CustomKeysAndValues.Builder()
+ .putString("string key", "string value")
+ .putString("string key 2", "string value 2")
+ .putBoolean("boolean key", true)
+ .putBoolean("boolean key 2", false)
+ .putFloat("float key", 1.01f)
+ .putFloat("float key 2", 2.02f)
+ .build())
+ ```
+
+5. Posteriormente compilamos la app y hacemos clic en SET INFO, y después en CRASH. La aplicación se detendrá y es necesario dirigirse a la pestaña de claves en Crashlytics.
+
+6. Ahora se registrará más información del usuario para el seguimiento de errores con los logs. Para ello agregamos la siguiente línea de código dentro del mismo evento.
+
+ ```kotlin
+ FirebaseCrashlytics.getInstance().log("Higgs-Boson detected! Bailing out")
+ ```
+
+7. Es posible agregar el userId y así averiguar más información. Para hacerlo se agrega la siguiente línea de código.
+
+ ```kotlin
+ FirebaseCrashlytics.getInstance().setUserId("12345")
+ ```
+
+8. Por último debe ejecutarse el proyecto, repetimos la operación de clic en SET INFO y en CRASH, dirigirse a Firebase, y ahí podrá visualizarse la información como en las siguientes pantallas.
+
+
+
+
+
+Así es posible consultar información del usuario y el ID, que corresponde al enviado en el código.
+
+¡Felicidades! Ahora tu app puede enviar información importante para la gestión de errores con Crashlytics.
+El siguiente reto te espera con el logro de gestionar y tipificar los errores.
+
+
+
+[Siguiente ](../Reto-02/README.md)(Reto 2)
\ No newline at end of file
diff --git a/Sesion-02/Ejemplo-03/assets/01.png b/Sesion-02/Ejemplo-03/assets/01.png
new file mode 100644
index 0000000..11f4d20
Binary files /dev/null and b/Sesion-02/Ejemplo-03/assets/01.png differ
diff --git a/Sesion-02/Ejemplo-03/assets/02.png b/Sesion-02/Ejemplo-03/assets/02.png
new file mode 100644
index 0000000..65b6d21
Binary files /dev/null and b/Sesion-02/Ejemplo-03/assets/02.png differ
diff --git a/Sesion-02/Ejemplo-03/assets/03.png b/Sesion-02/Ejemplo-03/assets/03.png
new file mode 100644
index 0000000..17e45c8
Binary files /dev/null and b/Sesion-02/Ejemplo-03/assets/03.png differ
diff --git a/Sesion-02/Ejemplo-03/assets/README.md b/Sesion-02/Ejemplo-03/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-02/Ejemplo-03/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-02/Postwork/README.md b/Sesion-02/Postwork/README.md
new file mode 100644
index 0000000..5f7287a
--- /dev/null
+++ b/Sesion-02/Postwork/README.md
@@ -0,0 +1,100 @@
+# Postwork 2 - Firebase Crashlytics - Reportes y seguimiento a errores
+
+## Objetivo
+
+- Habilitar notificaciones de errores en la app desde Firebase.
+- Configurar alertas de velocidad y datos de fallos de la app desde Firebase.
+- Configurar los informes de errores manual y automáticos desde Crashlytics.
+
+## Desarrollo
+
+En los ejemplos de esta sesión aprendimos a reconocer y gestionar los errores desde la consola de Firebase. Para el Postwork 02 queremos complementar lo aprendido.
+
+### Crashlytics tiene la posibilidad de:
+- Notificarnos por correo cuando se genera un error en la app.
+- Notificar cuando un problema individual genera otro urgente en una versión de la app.
+- Enviar todos los errores que se generen o solo enviarlos en algunas secciones de la app.
+
+### Indicaciones generales:
+1. Habilita en Crashlytics el envío de correos cuando se produzcan errores.
+ - Tip: en la parte superior derecha está el icono de notificaciones.
+2. Configura las alertas de velocidad, para recibir alertas cuando el error representa el 0.8% de las sesiones de los usuarios.
+ - Tip: en el menú de problemas puedes encontrar la opción para esta configuración.
+3. Configura tu proyecto para que sólo el MainActivity envíe los errores a Crashlytics.
+ - Tip: consulta la documentación para personalizar los informes de fallas. [Haz clic aquí para consultar la documentación.](https://firebase.google.com/docs/crashlytics/customize-crash-reports?hl=es-419&platform=android#enable-reporting)
+
+
+
+
+ Solución 1
+
+ - Clic en la campana “Parte superior derecha del Dashboard de Crashlytics”.
+
+
+
+ - Clic en el engranaje de configuración.
+
+
+
+ - Selecciona tu proyecto.
+
+
+
+ - Busca la sección de Crashlytics y habilita los check de Correo electrónico.
+ - Genera un nuevo error en la app; tiene que ser diferente a los enviados antes y se le puede cambiar el texto.
+ - Así, debe recibirse un correo con el error generado.
+
+
+
+
+
+
+
+
+
+
+ Solución 2
+
+- Las Alertas de velocidad y Configuración de datos de fallos se encuentran en el menú de la tabla de Problemas.
+- Al hacer clic despliega el siguiente menú y se selecciona la primer opción: Configuración de las alertas de velocidad.
+
+
+
+- En el siguiente modal puedes configurar el porcentaje permitido para el rango de tolerancia a incidencias repetidas por un periodo de tiempo.
+
+
+
+- La configuración de fallos está en la segunda opción del menú. Esta opción sirve para compartir la información de los crashes de tu app.
+
+
+
+
+
+
+
+
+ Solución 3
+
+- Para no admitir la configuración automática, en el bloque application del archivo AndroidManifest.xml, agrega una etiqueta meta-data para desactivar la recopilación automática:
+
+```xml
+
+```
+
+- Habilita la recopilación para usuarios específicos llamando a la anulación de recopilación de datos de Crashlytics durante el tiempo de ejecución.
+
+El valor de anulación persiste en todos los lanzamientos de tu app para que Crashlytics pueda recopilar informes automáticamente. Si quieres inhabilitar los informes automáticos de fallas, pasa false como el valor de anulación. Cuando se configura en false, el valor nuevo no se aplica hasta la próxima ejecución de la app.
+
+- Agrega el siguiente código en el método onCreate de tus activities para enviar los errores generados en esa vista: *FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)*
+
+
+
+
+
+
+
+[Regresar ](../README.md)(Sesión 02)
+
+[Siguiente ](../../Sesion-03/README.md)(Sesión 03)
\ No newline at end of file
diff --git a/Sesion-02/Postwork/assets/01.png b/Sesion-02/Postwork/assets/01.png
new file mode 100644
index 0000000..7247e45
Binary files /dev/null and b/Sesion-02/Postwork/assets/01.png differ
diff --git a/Sesion-02/Postwork/assets/02.png b/Sesion-02/Postwork/assets/02.png
new file mode 100644
index 0000000..8c9c20e
Binary files /dev/null and b/Sesion-02/Postwork/assets/02.png differ
diff --git a/Sesion-02/Postwork/assets/03.png b/Sesion-02/Postwork/assets/03.png
new file mode 100644
index 0000000..2145007
Binary files /dev/null and b/Sesion-02/Postwork/assets/03.png differ
diff --git a/Sesion-02/Postwork/assets/04.png b/Sesion-02/Postwork/assets/04.png
new file mode 100644
index 0000000..6a01451
Binary files /dev/null and b/Sesion-02/Postwork/assets/04.png differ
diff --git a/Sesion-02/Postwork/assets/05.png b/Sesion-02/Postwork/assets/05.png
new file mode 100644
index 0000000..163c2a8
Binary files /dev/null and b/Sesion-02/Postwork/assets/05.png differ
diff --git a/Sesion-02/Postwork/assets/06.png b/Sesion-02/Postwork/assets/06.png
new file mode 100644
index 0000000..018b2fc
Binary files /dev/null and b/Sesion-02/Postwork/assets/06.png differ
diff --git a/Sesion-02/Postwork/assets/07.png b/Sesion-02/Postwork/assets/07.png
new file mode 100644
index 0000000..779f2e6
Binary files /dev/null and b/Sesion-02/Postwork/assets/07.png differ
diff --git a/Sesion-02/Postwork/assets/08.png b/Sesion-02/Postwork/assets/08.png
new file mode 100644
index 0000000..daac403
Binary files /dev/null and b/Sesion-02/Postwork/assets/08.png differ
diff --git a/Sesion-02/README.md b/Sesion-02/README.md
new file mode 100644
index 0000000..d962816
--- /dev/null
+++ b/Sesion-02/README.md
@@ -0,0 +1,38 @@
+
+# :wave: Sesión 02: Firebase Crashlytics - Reportes y seguimiento a errores
+
+## 🎯 Objetivo de la sesión:
+
+- Gestionar Firebase Crashlytics en el código de la app para detectar y solucionar errores desde su sistema.
+
+## 🎯 Qué aprenderán
+
+- Implementación de firebase-crashlytics en un proyecto.
+- Generación de errores en un ambiente controlado.
+- Manejo del dashboard de Crashlytics.
+- Gestión de errores en Firebase Console.
+
+
+## ⚙ Requisitos
+
++ Revisión previa del prework de esta sesión
++ Cuenta de Google
++ Proyecto de Firebase
++ Android studio
+
+## 🎩 Desarrollo
+
+En esta sesión aprenderemos cuáles son los servicios de Firebase sumados con Crashlytics, cómo se implementa dentro de un proyecto de Android y de qué forma permite detectar, seguir y resolver errores generados en nuestra app. Para este propósito se generarán errores en un ambiente controlado y se gestionarán desde el dashboard de Firebase.
+
+Firebase Crashlytics proporciona reportes con estadísticas prácticas y claras sobre los problemas de la app, y basado en el establecimiento de comentarios del funcionamiento, así como seguimiento a los bugs a través de la plataforma de Firebase Console, con el propósito de resolver los fallos y brindar una experiencia de usuario satisfactoria.
+
+
+
+## 📂 Organización de la clase
+
+- [Ejemplo 01: Implementar Firebase Crashlytics](./Ejemplo-01/README.md)
+- [Ejemplo 02: Provocar un error controlado](./Ejemplo-02/README.md)
+ - [Reto 01: Dashboard Crashlytics](./Reto-01/README.md)
+- [Ejemplo 03: Funciones avanzadas](./Ejemplo-03/README.md)
+ - [Reto 02: Tipos de errores y su gestión](./Reto-02/README.md)
+- [Postwork: Reportes y seguimiento a errores](./Postwork/README.md)
\ No newline at end of file
diff --git a/Sesion-02/Reto-01/README.md b/Sesion-02/Reto-01/README.md
new file mode 100644
index 0000000..771369b
--- /dev/null
+++ b/Sesion-02/Reto-01/README.md
@@ -0,0 +1,70 @@
+# Reto 01: Dashboard Crashlytics
+
+## Objetivo
+
+- Interpretar el Dashboard de Crashlytics para gestionar errores de una app Android.
+- Discriminar los errores mediante las opciones de detección y seguimiento de Crashlytics.
+- Consultar el error generado previamente en Crashlytics.
+
+
+## Desarrollo
+
+En el ejemplo 2 se provocó un error y es momento de reconocer e interpretar el dashboard de Crashlytics para saber cómo gestionar los errores.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Nos dirigimos a la Console de Crashlytics. Ahí veremos una pantalla muy similar a la siguiente.
+
+
+
+2. Identifica las diferentes opciones de filtro de errores que ofrece el dashboard.
+
+
+ Solución
+
+ - Filtrar por versión de app y tipo de error.
+ - Seleccionar rango de fecha para visualizar errores por lapso de tiempo.
+ - Filtrar por estado del problema, dispositivo y sistema operativo.
+ - Buscar error por ID del usuario.
+
+ > Nota: Más adelante revisamos cada una de estas opciones
+
+
+
+
+
+3. Es momento de revisar el error generado previamente en nuestra app. Para ello haz clic en la tabla que se encuentra en la parte inferior, como se visualiza en la siguiente imagen.
+
+
+
+4. Después consulta las diferentes opciones que ofrece el detalle del error.
+
+
+ Solución
+
+ - Filtrar por versión de app, tipo de error, estado del problema, dispositivo y sistema operativo.
+ - Número de veces que se ha producido el error y a cuántos usuarios ha afectado.
+ - Filtrar por selección de rango de fecha.
+ - Eventos.
+ - Seguimiento de pila:
+ - Muestra qué, en dónde y porqué surgió el error.
+ - Claves:
+ - Datos enviados por la app. Se encuentra vacío porque aún no se revisará esa parte.
+ - Registros:
+ - Clase o vista donde se provocó el error.
+ - Datos:
+ - Información del Dispositivo (Hardware y Software).
+
+
+
+ > Nota: más adelante se utilizan cada una de estas opciones.
+
+
+
+
+
+
+
+
+
+[Siguiente ](../Ejemplo-03/README.md)(Ejemplo 3)
\ No newline at end of file
diff --git a/Sesion-02/Reto-01/assets/01.png b/Sesion-02/Reto-01/assets/01.png
new file mode 100644
index 0000000..44da5eb
Binary files /dev/null and b/Sesion-02/Reto-01/assets/01.png differ
diff --git a/Sesion-02/Reto-01/assets/02.png b/Sesion-02/Reto-01/assets/02.png
new file mode 100644
index 0000000..a85dc0b
Binary files /dev/null and b/Sesion-02/Reto-01/assets/02.png differ
diff --git a/Sesion-02/Reto-01/assets/03.png b/Sesion-02/Reto-01/assets/03.png
new file mode 100644
index 0000000..9742f16
Binary files /dev/null and b/Sesion-02/Reto-01/assets/03.png differ
diff --git a/Sesion-02/Reto-01/assets/README.md b/Sesion-02/Reto-01/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-02/Reto-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-02/Reto-02/README.md b/Sesion-02/Reto-02/README.md
new file mode 100644
index 0000000..48e1f26
--- /dev/null
+++ b/Sesion-02/Reto-02/README.md
@@ -0,0 +1,61 @@
+# Reto 02: Tipos de errores y su gestión
+
+## Objetivo
+
+- Implementar los dos tipos de errores y gestionarlos mediante las opciones del dashboard de Crashlytics.
+
+## Desarrollo
+
+Ya conociste el primer tipo de error: el producido en el Ejemplo 2. Este evento es de tipo Falla y es provocado cuando la app obtiene una excepción y no sabe cómo responder, por lo que el resultado es el cierre inesperado.
+
+El segundo tipo es Error recuperable. Este tipo sucede cuando agregamos un bloque de try / catch. Si el código dentro del try falla, es posible almacenar la excepción y Crashlytics enviará el error en algún momento, pues este error no tiene la misma prioridad que el otro y tardará más en enviarlo.
+
+Notas:
+- Crashlytics guarda máximo 64 kb del log en memoria para evitar saturar la app.
+- Los errores pueden tardar hasta 5 minutos en aparecer, por lo que debe tenerse paciencia si no aparecen rápido.
+
+Ahora que reconoces los tipos de errores y las formas de gestionarlos, sigue las indicaciones expuestas a continuación para resolver el reto 2.
+
+1. Genera un error recuperable dentro del clickListener del botón Crash.
+2. Después, genera una falla en el mismo evento, de modo que cierre la app.
+3. Gestiona los errores en Crashlytics:
+ - **a)** Agrega notas (Comentarios) a los errores generados, previamente
+ - **b)** Silencia el error indicando que ya corregiste el error y no tiene caso que te siga notificando, por lo que es posible cancelar los avisos.
+ - **c)** Cierra el error indicando que ya fue solucionado.
+
+
+
+
+ Solución 1-2
+
+ ```kotlin
+ binding.btnCrash.setOnClickListener {
+ //1
+ try {
+ Log.e(TAG, "handleClick: " + 0 / 0)
+ } catch (e: Exception) {
+ FirebaseCrashlytics.getInstance().recordException(e)
+ }
+ //2
+ throw RuntimeException("Test Crash") // Force a crash
+ }
+ ```
+
+
+
+
+
+ Solución 3
+a)
+
+
+b)
+
+
+c)
+
+
+
+
+
+[Siguiente ](../Postwork/README.md)(Postwork)
\ No newline at end of file
diff --git a/Sesion-02/Reto-02/assets/01.png b/Sesion-02/Reto-02/assets/01.png
new file mode 100644
index 0000000..2e0bd23
Binary files /dev/null and b/Sesion-02/Reto-02/assets/01.png differ
diff --git a/Sesion-02/Reto-02/assets/02.png b/Sesion-02/Reto-02/assets/02.png
new file mode 100644
index 0000000..30580b1
Binary files /dev/null and b/Sesion-02/Reto-02/assets/02.png differ
diff --git a/Sesion-02/Reto-02/assets/03.png b/Sesion-02/Reto-02/assets/03.png
new file mode 100644
index 0000000..b6d77ac
Binary files /dev/null and b/Sesion-02/Reto-02/assets/03.png differ
diff --git a/Sesion-02/Reto-02/assets/README.md b/Sesion-02/Reto-02/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-02/Reto-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-01/README.md b/Sesion-03/Ejemplo-01/README.md
new file mode 100644
index 0000000..6b9f8d2
--- /dev/null
+++ b/Sesion-03/Ejemplo-01/README.md
@@ -0,0 +1,136 @@
+# Ejemplo 01: Dependencias manuales
+
+## Objetivo
+
+* Crear un proyecto Android con y sin la inyección de dependencias para comparar los beneficios en el desarrollo.
+
+## Desarrollo
+
+Se creará un proyecto Android desde cero, el cual evitará la inyección de dependencias. Después, se modificará para que implemente la inyección de dependencias con el propósito de evidenciar las propuestas de desarrollo de apps y así comparar sus beneficios.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Dirígete a Android Studio, crea un nuevo proyecto y selecciona la opción de No Activity, como se visualiza en la siguiente imagen.
+
+
+
+2. Nombra el proyecto como desees; te recomendamos llamarlo Dependencias. Posteriormente haz clic en Finish.
+
+
+
+3. Después debe crearse una Clase de Kotlin, como se aprecia en la imagen.
+
+
+
+4. En la clase creada se debe agregar el siguiente código.
+
+ ```Kotlin
+ class Engine {
+ fun start() {
+ println("engine.start()")
+ }
+ }
+
+ class Car {
+ private val engine = Engine()
+
+ fun start() {
+ engine.start()
+ }
+ }
+
+ fun main() {
+ val car = Car()
+ car.start()
+ }
+ ```
+
+5. Ahora se ejecuta el proyecto y el resultado que se visualiza debería ser el siguiente.
+
+
+
+ Este no es un ejemplo de inyección de dependencias porque la clase Car está construyendo su propio Engine, lo que puede ocasionar problemas a causa de las razones siguientes:
+
+ - Car y Engine están estrechamente vinculados: una instancia de Car usa un tipo de Engine, y no se pueden utilizar subclases ni implementaciones alternativas con facilidad. Si el Car construyera su propio Engine, tendría que crear dos tipos de Car en lugar de solo reutilizar el mismo Car para motores de tipo Gas y Electric.
+ - La dependencia estricta de Engine hace que las pruebas sean más difíciles. Car usa una instancia real de Engine, lo que impide utilizar un doble de prueba y modificar Engine para diferentes casos de prueba.
+
+
+
+6. Ahora modificaremos el código para implementar dependencias manualmente. Debe resultar de la siguiente forma.
+
+ ```Kotlin
+ class Engine {
+ fun start() {
+ println("engine.start()")
+ }
+ }
+
+ class Car(private val engine: Engine) {
+ fun start() {
+ engine.start()
+ }
+ }
+
+ fun main() {
+ val engine = Engine()
+ val car = Car(engine)
+ car.start()
+ }
+ ```
+
+7. Después debe ejecutarse el código. Resulta lo que se aprecia en la siguiente imagen.
+
+
+
+ Al observar el resultado es el mismo, ¿entonces qué cambió?
+ R: la función main usa Car. Debido a que Car depende de Engine, la app crea una instancia de Engine y luego la usa para construir una instancia de Car.
+
+ Los beneficios de este enfoque basado en DI, o inyección de dependencias, son los siguientes:
+
+ - Reutilización de Car. Se pueden pasar diferentes implementaciones de Engine a Car. Por ejemplo, se puede definir una nueva subclase de Engine, llamada ElectricEngine para utilizar con Car. Si se usa DI sólo se debe pasar una instancia de la subclase actualizada de ElectricEngine y Car seguirá funcionando sin más cambios.
+ - Prueba fácil de Car. Se pueden pasar [dobles de prueba](https://www.genbeta.com/desarrollo/desmitificando-los-dobles-de-test-mocks-stubs-and-friends) para probar diferentes situaciones. Por ejemplo, es posible crear un doble de prueba de Engine llamado FakeEngine, y configurarlo para diferentes pruebas.
+
+
+
+ Se puede pasar las dependencias por el constructor o con el método set. En el paso previo lo hicimos con el constructor, y en el siguiente paso lo haremos por el método set, denominado también inyección de campo.
+
+8. Ahora es necesario modificar un poco el código para pasar dependencias por el método set, y se deja el código anterior comentado para tenerlo de referencia. El resultado debe ser el siguiente.
+
+ ```Kotlin
+ class Engine {
+ fun start() {
+ println("engine.start()")
+ }
+ }
+
+ // Dependencias por el constructor
+ class Car(private val engine: Engine) {
+ fun start() {
+ engine.start()
+ }
+ }
+ // Dependencias por el método set
+ class Car2{
+ lateinit var engine: Engine
+
+ fun start() {
+ engine.start()
+ }
+ }
+
+ fun main() {
+ val engine = Engine()
+ // Dependencias por el constructor
+ val car = Car(engine)
+ car.start()
+
+ // Dependencias por el método set
+ val car2 = Car2()
+ car2.engine = Engine()
+ car.start()
+ }
+ ```
+
+
+
+[Siguiente ](../Ejemplo-02/README.md)(Ejemplo 2)
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-01/assets/01.png b/Sesion-03/Ejemplo-01/assets/01.png
new file mode 100644
index 0000000..c1290eb
Binary files /dev/null and b/Sesion-03/Ejemplo-01/assets/01.png differ
diff --git a/Sesion-03/Ejemplo-01/assets/02.png b/Sesion-03/Ejemplo-01/assets/02.png
new file mode 100644
index 0000000..c93a9f0
Binary files /dev/null and b/Sesion-03/Ejemplo-01/assets/02.png differ
diff --git a/Sesion-03/Ejemplo-01/assets/03.png b/Sesion-03/Ejemplo-01/assets/03.png
new file mode 100644
index 0000000..2d3bccf
Binary files /dev/null and b/Sesion-03/Ejemplo-01/assets/03.png differ
diff --git a/Sesion-03/Ejemplo-01/assets/04.png b/Sesion-03/Ejemplo-01/assets/04.png
new file mode 100644
index 0000000..fd990bd
Binary files /dev/null and b/Sesion-03/Ejemplo-01/assets/04.png differ
diff --git a/Sesion-03/Ejemplo-01/assets/README.md b/Sesion-03/Ejemplo-01/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-03/Ejemplo-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-02/README.md b/Sesion-03/Ejemplo-02/README.md
new file mode 100644
index 0000000..3c6f842
--- /dev/null
+++ b/Sesion-03/Ejemplo-02/README.md
@@ -0,0 +1,228 @@
+# Ejemplo 02: Implementar Dagger Hilt
+
+## Objetivo
+
+* Implementar la inyección de dependencias de manera automatizada mediante Dagger Hilt y evitar problemas de inyección manual.
+
+## Desarrollo
+
+En el ejemplo anterior se crearon, proporcionaron y administraron por cuenta propia las dependencias de las diferentes clases, sin recurrir a una biblioteca. Esto se denomina inyección de dependencias a mano o inyección de dependencias manual.
+
+En el ejemplo de Car sólo había una dependencia, pero si hay varias dependencias y clases la inyección manual resulta más difícil y tediosa, además de que presenta los siguientes problemas:
+
+- En el caso de aplicaciones grandes, tomar las dependencias y conectarlas correctamente puede requerir una gran cantidad de código estándar. En una arquitectura de varias capas, para crear un objeto en una capa superior, se deben proporcionar todas las dependencias de las capas que se encuentran debajo de ella. Por ejemplo, para construir un automóvil real es posible que necesites un motor, una transmisión, un chasis y otras piezas; a su vez, el motor necesita cilindros y bujías.
+
+- Cuando no se pueden construir dependencias antes de pasarlas (por ejemplo, si usas inicializaciones diferidas, o si solicitas permisos para objetos en los flujos de tu app), necesitas escribir y conservar un contenedor personalizado (o un grafo de dependencias) que administre las dependencias en la memoria desde el principio.
+
+Debido a estos inconvenientes Hilt es la biblioteca de Jetpack recomendada para la inyección de dependencias en Android. Hilt establece una forma estándar de usar la inyección de dependencias en tu aplicación, pues proporciona contenedores para cada clase de Android en tu proyecto y administra sus ciclos de vida de forma automática.
+
+Se basa en la popular biblioteca de inyección de dependencias Dagger y se beneficia de la corrección en tiempo de compilación, el rendimiento del entorno de ejecución, la escalabilidad, y la compatibilidad con Android Studio que proporciona.
+
+Ahora utilizaremos el proyecto del ejemplo 1 y lo prepararemos para trabajar con Hilt. Para hacerlo realiza los siguientes pasos.
+
+1. Dirígete al Gradle del proyecto y agrega la siguiente línea de código, como se aprecia en la imagen.
+
+ ```Gradle
+ classpath "com.google.dagger:hilt-android-gradle-plugin:2.36"
+ ```
+
+
+
+2. Ahora debe abrirse el Gradle del módulo y ahí es necesario agregar las siguientes líneas de código, como se visualiza en las imágenes.
+
+ ```Gradle
+ id 'kotlin-kapt'
+ id 'dagger.hilt.android.plugin'
+
+ ...
+
+ //Dagger - Hilt
+ implementation "com.google.dagger:hilt-android:2.36"
+ kapt "com.google.dagger:hilt-android-compiler:2.36"
+ ```
+
+
+
+
+
+3. Después se debe crear una clase que será llamada Application.
+
+
+
+4. Es necesario que se le agregue el siguiente código.
+
+ ```Gradle
+ import android.app.Application
+ import dagger.hilt.android.HiltAndroidApp
+
+ @HiltAndroidApp
+ class Application : Application()
+ ```
+
+ > Nota: con la anotación **@HiltAndroidApp** indicamos a Hilt que tiene que implementar la inyección de dependencias en nuestra app.
+
+5. Posteriormente debe crearse el object **AppModule**. Este será el encargado de pasar las dependencias que se adhieran. Debe agregarse el siguiente código dentro de él, el cual contiene la primera dependencia.
+
+
+
+ ```Gradle
+ import dagger.Module
+ import dagger.Provides
+ import dagger.hilt.InstallIn
+ import dagger.hilt.components.SingletonComponent
+ import javax.inject.Named
+ import javax.inject.Singleton
+
+ @Module
+ @InstallIn(SingletonComponent::class)
+ object AppModule {
+
+ @Singleton
+ @Provides
+ @Named("String1")
+ fun provideTestString1() = "This is string to inject"
+
+ }
+ ```
+
+ La explicación de las anotaciones usadas en el código son las siguientes.
+
+ - **@Module.** Tiene la función de especificar que el objeto es un módulo y contiene dependencias.
+ - **@InstallIn.** Indica a Hilt en qué clase de Android se usará o instalará cada módulo.
+ - **@Singleton.** Expresa que la dependencia sólo se puede instanciar una vez.
+ - **@Provides.** Indica que el valor resultante será enviado a quien lo implemente.
+ - **@Named.** Expresa el nombre que se brinda a la dependencia, y quién lo quiera implementar tendrá que buscarla por el nombre que se defina dentro del named, o de lo contrario toma el valor de la función.
+
+
+
+6. Luego debe crearse el **MainActivity** que inyecta la dependencia del **AppModule**. Para ello se agrega el siguiente código de manera que resulte como se aprecia a continuación.
+
+ ```Gradle
+ import android.os.Bundle
+ import android.util.Log
+ import androidx.appcompat.app.AppCompatActivity
+ import dagger.hilt.android.AndroidEntryPoint
+ import javax.inject.Inject
+ import javax.inject.Named
+
+ @AndroidEntryPoint
+ class MainActivity : AppCompatActivity() {
+
+ @Inject
+ @Named("String1")
+ lateinit var testString: String
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ Log.e("MainActivity", testString)
+ }
+ }
+ ```
+
+ Con la anotación **@Inject** se indica a Hilt que inyecte la dependencia que se expresó en el Named.
+
+ Ahora, para ejecutar el código necesitamos realizar algunos pasos extra que se indican a continuación.
+
+7. Se crea el **activity_main** con el siguiente código XML.
+
+
+
+ ```xml
+
+
+
+
+ ```
+
+ Hasta este punto nuestra app no posee interfaz, por lo que el XML se encuentra vacío.
+
+8. Posteriormente modificamos el **AndroidManifest** para que implemente Hilt y acepte el **MainActivity** recién creado y se reemplaza el **Application** con el siguiente código XML.
+
+ ```xml
+
+
+
+
+
+
+
+
+
+ ```
+
+9. Ahora debe ejecutarse el proyecto. El **LogCat** debería mostrar la siguiente línea visualizada en la imagen.
+
+
+
+ Eso significa que la dependencia está funcionando correctamente.
+
+ El módulo creado inyectará dependencias a todo el proyecto, por eso se agregó SingletonComponent en el InstallIn del AppModule.
+
+10. Ahora se creará un módulo que inyecte dependencias a las **Activities** y se apegue a su ciclo de vida. Para realizarlo crea el Objeto **MainModule** con el siguiente código.
+
+ ```Kotlin
+ import android.content.Context
+ import dagger.Module
+ import dagger.Provides
+ import dagger.hilt.InstallIn
+ import dagger.hilt.android.components.ActivityComponent
+ import dagger.hilt.android.qualifiers.ApplicationContext
+ import dagger.hilt.android.scopes.ActivityScoped
+ import javax.inject.Named
+
+ @Module
+ @InstallIn(ActivityComponent::class)
+ object MainModule {
+
+ @ActivityScoped
+ @Provides
+ @Named("String2")
+ fun provideTestString2(
+ @ApplicationContext context: Context,
+ @Named("String1") testString1: String
+ ) = "${context.getString(R.string.string_to_inject)} - $testString1"
+ }
+ ```
+
+11. La anotación **@ActivityScoped** fue agregada para que este módulo trabaje con el ciclo de vida del **Activity**. Además, la dependencia solicita un **string** desde los recursos, el cual debemos crear. Para ello se le puede agregar el siguiente código, de modo que resulte como se aprecia en la siguiente imagen.
+
+
+
+12. Ahora es necesario dirigirse al **MainActivity**, inyectar la dependencia e imprimirla en el **onCreate** mediante el siguiente código.
+
+ ```Kotlin
+ @Inject
+ @Named("String2")
+ lateinit var testString2: String
+
+ …
+
+ Log.e("MainActivity", testString2)
+ ```
+
+13. Posteriormente se ejecuta el proyecto. El resultado debería ser como el de la imagen, lo que representa que las dependencias, tanto del Application como del Activity, fueron inyectadas correctamente.
+
+
+
+
+
+
+¡Felicidades! Ahora puedes inyectar dependencias en tu proyecto Android con Dagger Hilt.
+El siguiente reto te espera para practicar lo aprendido.
+
+
+
+
+[Siguiente ](../Reto-01/README.md)(Reto 1)
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-02/assets/01.png b/Sesion-03/Ejemplo-02/assets/01.png
new file mode 100644
index 0000000..131028c
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/01.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/02.png b/Sesion-03/Ejemplo-02/assets/02.png
new file mode 100644
index 0000000..dbe8b3a
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/02.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/03.png b/Sesion-03/Ejemplo-02/assets/03.png
new file mode 100644
index 0000000..b5bc607
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/03.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/04.png b/Sesion-03/Ejemplo-02/assets/04.png
new file mode 100644
index 0000000..af8cdcc
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/04.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/05.png b/Sesion-03/Ejemplo-02/assets/05.png
new file mode 100644
index 0000000..b17c33e
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/05.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/06.png b/Sesion-03/Ejemplo-02/assets/06.png
new file mode 100644
index 0000000..8913085
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/06.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/07.png b/Sesion-03/Ejemplo-02/assets/07.png
new file mode 100644
index 0000000..891ce85
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/07.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/08.png b/Sesion-03/Ejemplo-02/assets/08.png
new file mode 100644
index 0000000..e9b9f32
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/08.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/09.png b/Sesion-03/Ejemplo-02/assets/09.png
new file mode 100644
index 0000000..a41a3dd
Binary files /dev/null and b/Sesion-03/Ejemplo-02/assets/09.png differ
diff --git a/Sesion-03/Ejemplo-02/assets/README.md b/Sesion-03/Ejemplo-02/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-03/Ejemplo-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/README.md b/Sesion-03/Ejemplo-03/README.md
new file mode 100644
index 0000000..cf846f2
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/README.md
@@ -0,0 +1,256 @@
+# Ejemplo 03: Consumir API
+
+## Objetivo
+
+* Distinguir dependencias que envíen peticiones para consumir servicios de API (Backend) y que al obtener la información la representen en la vista mediante Dagger Hilt y Retrofit.
+
+## Desarrollo
+
+Esta vez se trabajará el [Proyecto base](./base) con el propósito de distinguir cómo se aplicaron las dependencias para el consumo de servicios de una API, situación que permite la implementación de nuevos módulos (Pantallas) y el ahorro de código.
+Una vez identificado el modo, y analizado el funcionamiento del proyecto, será momento de ejemplificar lo aprendido al implementar el módulo restante. Para hacerlo realiza los siguientes pasos.
+
+1. Ejecuta el proyecto base con Android Studio. Este desplegará la siguiente interfaz.
+
+
+
+ Al hacer clic en el botón de **People** la app se conectará a la api [Swapi](https://swapi.dev/api/) y solicitará los personajes de StarWars mediante Retrofit y dependencias. Una vez que la API responda se visualizará la siguiente interfaz.
+
+
+
+ Ahora conoces la interfaz y su navegación. A partir de aquí se revisarán los módulos. Para ello realiza lo que se solicita en las instrucciones e identifica las funciones.
+
+2. Al igual que en el proyecto del Ejemplo 2, Hilt necesita envolver la App para configurar e inyectar las dependencias, Esto se encuentra en la clase **App**.
+
+ Hasta el momento el **MainActivity** sólo está encargado de abrir el PeopleActivity; por ahora el **PlanetsActivity** no tiene ninguna función.
+
+3. La interfaz **ApiHelper** se encarga de asignar los servicios que se solicitarán al API. Sólo tiene una función, la que obtiene los personajes; su código es el siguiente.
+
+ ```Kotlin
+ interface ApiHelper {
+ suspend fun getPeople(): Response
+ }
+ ```
+
+4. Así como la interfaz **ApiHelper**, **ApiService** dispone de las funciones que se van a ejecutar del API. La única diferencia es que en esta clase se agrega el verbo HTTP y una parte de la URL del servicio, como se aprecia a continuación.
+
+ ```Kotlin
+ interface ApiService {
+ @GET("people")
+ suspend fun getPeople(): Response
+ }
+ ```
+
+5. El **ApiHelperImpl** está encargado de implementar el **ApiHelper** y el **ApiService**, y aquí es donde empieza la magia de las dependencias, es decir, su operación. Para ello se requiere inyectar las dos interfaces, provocando la utilización de sus funciones. Hasta ahora sólo se tiene una en cada interfaz. El código debe resultar de la siguiente manera.
+
+ ```Kotlin
+ class ApiHelperImpl @Inject constructor(private val apiService: ApiService) : ApiHelper {
+
+ override suspend fun getPeople(): Response = apiService.getPeople()
+
+ }
+ ```
+
+6. Hasta el momento, las funciones empleadas usan el modelo **ResponsePeopleModel**. En este se encuentra la estructura del Json que se recibirá cuando se ejecute la petición, como se distingue a continuación.
+
+ ```Kotlin
+ data class ResponsePeopleModel(
+ @Json(name = "count")
+ val count: Int = 0,
+ @Json(name = "next")
+ val next: String = "",
+ @Json(name = "previous")
+ val previous: String = "",
+ @Json(name = "results")
+ val results: List = ArrayList()
+ )
+ ```
+
+7. La clase **MainRepository** inyecta las dependencias, conectándolas con la vista, como se visualiza.
+
+ ```Kotlin
+ class MainRepository @Inject constructor(private val apiHelper: ApiHelper) {
+
+ suspend fun getPeople() = apiHelper.getPeople()
+
+ }
+ ```
+
+8. El **ApplicationModule** contiene todas la dependencias que utiliza nuestra app. En este momento se revisará una a una:
+
+ - **provideBaseUrl**
+ - Obtiene la URL base del API a consultar.
+ - **provideOkHttpClient**
+ - Configura el cliente para realizar las peticiones con Retrofit.
+ - **provideRetrofit**
+ - Inicializa a retrofit pasándole el okHttpCliente previamente creado y la URL base del proyecto.
+ - **provideApiService y provideApiHelper**
+ - Son enviados como parámetro en el constructor del ApiHelperImpl para realizar las peticiones. Nota: en una comparación analógica, este sería el motor visto en el ejemplo 1.
+
+
+
+ Las contiene de la siguiente forma.
+
+ ```Kotlin
+ @Module
+ @InstallIn(SingletonComponent::class)
+ class ApplicationModule {
+
+ @Provides
+ fun provideBaseUrl() = BuildConfig.BASE_URL
+
+ @Provides
+ @Singleton
+ fun provideOkHttpClient() = if (BuildConfig.DEBUG) {
+ val loggingInterceptor = HttpLoggingInterceptor()
+ loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ OkHttpClient.Builder()
+ .addInterceptor(loggingInterceptor)
+ .build()
+ } else OkHttpClient
+ .Builder()
+ .build()
+
+
+ @Provides
+ @Singleton
+ fun provideRetrofit(
+ okHttpClient: OkHttpClient,
+ BASE_URL: String
+ ): Retrofit =
+ Retrofit.Builder()
+ .addConverterFactory(MoshiConverterFactory.create())
+ .baseUrl(BASE_URL)
+ .client(okHttpClient)
+ .build()
+
+ @Provides
+ @Singleton
+ fun provideApiService(retrofit: Retrofit): ApiService = retrofit.create(ApiService::class.java)
+
+ @Provides
+ @Singleton
+ fun provideApiHelper(apiHelper: ApiHelperImpl): ApiHelper = apiHelper
+
+ }
+ ```
+
+9. Después se debe dirigir al **PeopleViewModel**. Al ser un **viewModel** requiere que se le agregue la anotación **@HiltViewModel**, y con **@Inject** se implementan las dependencias que necesita para realizar las peticiones. En primer lugar está el **MainRepository**, y posteriormente el **NetworkHelper**. El segundo tiene la responsabilidad de comprobar la conexión a internet y retorna un booleano para indicar el estatus de la conexión.
+
+10. El **viewModel** de **People** contiene la variable _people, utilizada para enviar el resultado de la llamada al servicio web. Además contiene tres funciones, dos de ellas, **init** y **onRefresh**, se encargan de llamar a la tercera, la que lanza la petición al servicio web y espera que este complete su ejecución. Al terminar envía los resultados, sean positivos o negativos, al **PeopleActivity**, que se ocupará de pintar los datos. El código resulta de la siguiente manera.
+
+ ```Kotlin
+ @HiltViewModel
+ class PeopleViewModel @Inject constructor(
+ private val mainRepository: MainRepository,
+ private val networkHelper: NetworkHelper
+ ) : ViewModel() {
+
+ private val _people = MutableLiveData>>()
+ val people: LiveData>>
+ get() = _people
+
+ init {
+ fetchUsers()
+ }
+
+ fun onRefresh() {
+ fetchUsers()
+ }
+
+ private fun fetchUsers() {
+ viewModelScope.launch {
+ _people.postValue(Resource.loading(null))
+ if (networkHelper.isNetworkConnected()) {
+ mainRepository.getPeople().let {
+ if (it.isSuccessful) {
+ _people.postValue(Resource.success(it.body()?.results))
+ } else _people.postValue(Resource.error(it.errorBody().toString(), null))
+ }
+ } else _people.postValue(Resource.error("No internet connection", null))
+ }
+ }
+ }
+ ```
+
+11. **PeopleActivity** carga la vista que incluye la lista y la función de **swipeRefresh**, así como el adaptador que está esperando cambios para actualizar la vista.
+No se abordará el funcionamiento de estos elementos pues se revisaron en el módulo anterior. Si deseas consultar información al respecto dirígete al siguiente vínculo.
+
+ [Haz clic aquí si deseas consultar la documentación oficial sobre listas dinámicas RecyclerView.](https://developer.android.com/guide/topics/ui/layout/recyclerview?hl=es-419)
+
+ El **Activity** de **People** agrega **observe** por medio del **viewModel** para escuchar los eventos de People y así pintar la vista. El código que resulta es el siguiente.
+
+ ```Kotlin
+ @AndroidEntryPoint
+ class PeopleActivity : AppCompatActivity() {
+
+ private val peopleViewModel : PeopleViewModel by viewModels()
+ private lateinit var adapter: PeopleAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_recycler)
+ setupUI()
+ setupObserver()
+ }
+
+ private fun setupUI() {
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ adapter = PeopleAdapter(arrayListOf())
+ recyclerView.addItemDecoration(
+ DividerItemDecoration(
+ recyclerView.context,
+ (recyclerView.layoutManager as LinearLayoutManager).orientation
+ )
+ )
+ recyclerView.adapter = adapter
+ swipeRefreshLayout.setOnRefreshListener {
+ peopleViewModel.onRefresh()
+ }
+ }
+
+ private fun setupObserver() {
+ peopleViewModel.people.observe(this, Observer {
+ swipeRefreshLayout.isRefreshing = false
+ when (it.status) {
+ Status.SUCCESS -> {
+ progressBar.visibility = View.GONE
+ it.data?.let { people -> renderList(people) }
+ recyclerView.visibility = View.VISIBLE
+ }
+ Status.LOADING -> {
+ progressBar.visibility = View.VISIBLE
+ recyclerView.visibility = View.GONE
+ }
+ Status.ERROR -> {
+ //Handle Error
+ progressBar.visibility = View.GONE
+ Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
+ }
+ }
+ })
+ }
+
+ private fun renderList(people: List) {
+ adapter.addData(people)
+ adapter.notifyDataSetChanged()
+ }
+ }
+ ```
+
+12. **Resource** y **Status** sólo contienen las respuestas posibles para las peticiones lanzadas al API:
+
+ - SUCCESS
+ - ERROR
+ - LOADING
+
+
+
+
+¡Felicidades! Hemos concluido con la revisión de la estructura y funcionamiento de la app de Star Wars. Si tienes alguna inquietud comunícala a tu experto.
+
+El siguiente reto te espera con el logro de implementar el módulo de Planets reutilizando el código existente.
+
+
+
+
+[Siguiente ](../Reto-02/README.md)(Reto 2)
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/assets/01.png b/Sesion-03/Ejemplo-03/assets/01.png
new file mode 100644
index 0000000..35e62fa
Binary files /dev/null and b/Sesion-03/Ejemplo-03/assets/01.png differ
diff --git a/Sesion-03/Ejemplo-03/assets/02.png b/Sesion-03/Ejemplo-03/assets/02.png
new file mode 100644
index 0000000..2154eac
Binary files /dev/null and b/Sesion-03/Ejemplo-03/assets/02.png differ
diff --git a/Sesion-03/Ejemplo-03/assets/README.md b/Sesion-03/Ejemplo-03/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/.gitignore b/Sesion-03/Ejemplo-03/base/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/Sesion-03/Ejemplo-03/base/app/.gitignore b/Sesion-03/Ejemplo-03/base/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/build.gradle b/Sesion-03/Ejemplo-03/base/app/build.gradle
new file mode 100644
index 0000000..d246578
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/build.gradle
@@ -0,0 +1,74 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'kotlin-kapt'
+ id 'dagger.hilt.android.plugin'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ applicationId "com.bedu.hilt"
+ minSdkVersion 19
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ buildConfigField 'String', 'BASE_URL', "\"https://swapi.dev/api/\""
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+ buildFeatures {
+ viewBinding = true
+ }
+}
+
+dependencies {
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'com.google.android.material:material:1.3.0'
+
+ // Added Dependencies
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
+ implementation "androidx.recyclerview:recyclerview:1.2.1"
+ implementation 'com.github.bumptech.glide:glide:4.12.0'
+ implementation 'androidx.activity:activity-ktx:1.2.3'
+
+ // hilt
+ implementation "com.google.dagger:hilt-android:2.36"
+ kapt "com.google.dagger:hilt-compiler:2.36"
+ kapt "androidx.hilt:hilt-compiler:1.0.0"
+
+ // Networking
+ implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
+ implementation "com.squareup.retrofit2:retrofit:2.9.0"
+ implementation "com.squareup.okhttp3:okhttp:4.9.0"
+ implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
+
+ //Coroutine
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0"
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0"
+
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/proguard-rules.pro b/Sesion-03/Ejemplo-03/base/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/androidTest/java/com/bedu/hilt/ExampleInstrumentedTest.kt b/Sesion-03/Ejemplo-03/base/app/src/androidTest/java/com/bedu/hilt/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..0680354
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/androidTest/java/com/bedu/hilt/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.bedu.hilt
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.bedu.hilt", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/AndroidManifest.xml b/Sesion-03/Ejemplo-03/base/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3703a82
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/App.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/App.kt
new file mode 100644
index 0000000..5a2b159
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/App.kt
@@ -0,0 +1,7 @@
+package com.bedu.hilt
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class App : Application()
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelper.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelper.kt
new file mode 100644
index 0000000..f946f06
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelper.kt
@@ -0,0 +1,9 @@
+package com.bedu.hilt.data.api
+
+import com.bedu.hilt.data.model.ResponsePeopleModel
+import retrofit2.Response
+
+interface ApiHelper {
+
+ suspend fun getPeople(): Response
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelperImpl.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelperImpl.kt
new file mode 100644
index 0000000..6e04076
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiHelperImpl.kt
@@ -0,0 +1,11 @@
+package com.bedu.hilt.data.api
+
+import com.bedu.hilt.data.model.ResponsePeopleModel
+import retrofit2.Response
+import javax.inject.Inject
+
+class ApiHelperImpl @Inject constructor(private val apiService: ApiService) : ApiHelper {
+
+ override suspend fun getPeople(): Response = apiService.getPeople()
+
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiService.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiService.kt
new file mode 100644
index 0000000..e909907
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/api/ApiService.kt
@@ -0,0 +1,12 @@
+package com.bedu.hilt.data.api
+
+import com.bedu.hilt.data.model.ResponsePeopleModel
+import retrofit2.Response
+import retrofit2.http.GET
+
+interface ApiService {
+
+ @GET("people")
+ suspend fun getPeople(): Response
+
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/People.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/People.kt
new file mode 100644
index 0000000..30ed2f6
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/People.kt
@@ -0,0 +1,17 @@
+package com.bedu.hilt.data.model
+
+import com.squareup.moshi.Json
+
+
+data class People(
+ @Json(name = "id")
+ val id: Int = 0,
+ @Json(name = "name")
+ val name: String = "",
+ @Json(name = "gender")
+ val gender: String = "",
+ @Json(name = "hair_color")
+ val hairColor: String = "",
+ @Json(name = "avatar")
+ val avatar: String = ""
+)
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/ResponsePeopleModel.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/ResponsePeopleModel.kt
new file mode 100644
index 0000000..dd6784e
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/model/ResponsePeopleModel.kt
@@ -0,0 +1,14 @@
+package com.bedu.hilt.data.model
+
+import com.squareup.moshi.Json
+
+data class ResponsePeopleModel(
+ @Json(name = "count")
+ val count: Int = 0,
+ @Json(name = "next")
+ val next: String = "",
+ @Json(name = "previous")
+ val previous: String = "",
+ @Json(name = "results")
+ val results: List = ArrayList()
+)
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/repository/MainRepository.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/repository/MainRepository.kt
new file mode 100644
index 0000000..8accbd6
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/data/repository/MainRepository.kt
@@ -0,0 +1,10 @@
+package com.bedu.hilt.data.repository
+
+import com.bedu.hilt.data.api.ApiHelper
+import javax.inject.Inject
+
+class MainRepository @Inject constructor(private val apiHelper: ApiHelper) {
+
+ suspend fun getPeople() = apiHelper.getPeople()
+
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/di/module/ApplicationModule.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/di/module/ApplicationModule.kt
new file mode 100644
index 0000000..ec6d2a1
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/di/module/ApplicationModule.kt
@@ -0,0 +1,57 @@
+package com.bedu.hilt.di.module
+
+import com.bedu.hilt.BuildConfig
+import com.bedu.hilt.data.api.ApiHelper
+import com.bedu.hilt.data.api.ApiHelperImpl
+import com.bedu.hilt.data.api.ApiService
+import dagger.Module
+import dagger.Provides
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import javax.inject.Singleton
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.converter.moshi.MoshiConverterFactory
+
+@Module
+@InstallIn(SingletonComponent::class)
+class ApplicationModule {
+
+ @Provides
+ fun provideBaseUrl() = BuildConfig.BASE_URL
+
+ @Provides
+ @Singleton
+ fun provideOkHttpClient() = if (BuildConfig.DEBUG) {
+ val loggingInterceptor = HttpLoggingInterceptor()
+ loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ OkHttpClient.Builder()
+ .addInterceptor(loggingInterceptor)
+ .build()
+ } else OkHttpClient
+ .Builder()
+ .build()
+
+
+ @Provides
+ @Singleton
+ fun provideRetrofit(
+ okHttpClient: OkHttpClient,
+ BASE_URL: String
+ ): Retrofit =
+ Retrofit.Builder()
+ .addConverterFactory(MoshiConverterFactory.create())
+ .baseUrl(BASE_URL)
+ .client(okHttpClient)
+ .build()
+
+ @Provides
+ @Singleton
+ fun provideApiService(retrofit: Retrofit): ApiService = retrofit.create(ApiService::class.java)
+
+ @Provides
+ @Singleton
+ fun provideApiHelper(apiHelper: ApiHelperImpl): ApiHelper = apiHelper
+
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/main/view/MainActivity.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/main/view/MainActivity.kt
new file mode 100644
index 0000000..136aa89
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/main/view/MainActivity.kt
@@ -0,0 +1,33 @@
+package com.bedu.hilt.ui.main.view
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.bedu.hilt.databinding.ActivityMainBinding
+import com.bedu.hilt.ui.people.view.PeopleActivity
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class MainActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityMainBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ setupUI()
+ }
+
+ private fun setupUI() {
+ binding.btnPeople.setOnClickListener {
+ val intent = Intent(this, PeopleActivity::class.java)
+ startActivity(intent)
+ }
+ binding.btnPlanets.setOnClickListener {
+ }
+ }
+}
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/adapter/PeopleAdapter.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/adapter/PeopleAdapter.kt
new file mode 100644
index 0000000..9541ecc
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/adapter/PeopleAdapter.kt
@@ -0,0 +1,46 @@
+package com.bedu.hilt.ui.people.adapter
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.bedu.hilt.R
+import com.bedu.hilt.data.model.People
+import com.bedu.hilt.databinding.ItemLayoutBinding
+import com.bumptech.glide.Glide
+
+class PeopleAdapter(
+ private val people: ArrayList,
+) : RecyclerView.Adapter() {
+
+ class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ fun bind(model: People) {
+
+ val binding = ItemLayoutBinding.bind(itemView)
+
+ binding.textViewUserName.text = model.name
+ binding.textViewUserEmail.text = model.gender
+ Glide.with(binding.imageViewAvatar.context)
+ .load("")
+ .into(binding.imageViewAvatar)
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ DataViewHolder(
+ LayoutInflater.from(parent.context).inflate(
+ R.layout.item_layout, parent,
+ false
+ )
+ )
+
+ override fun getItemCount(): Int = people.size
+
+ override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
+ holder.bind(people[position])
+
+ fun addData(list: List) {
+ people.clear()
+ people.addAll(list)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/view/PeopleActivity.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/view/PeopleActivity.kt
new file mode 100644
index 0000000..5bb1c25
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/view/PeopleActivity.kt
@@ -0,0 +1,77 @@
+package com.bedu.hilt.ui.people.view
+
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.bedu.hilt.data.model.People
+import com.bedu.hilt.databinding.ActivityRecyclerBinding
+import com.bedu.hilt.ui.people.adapter.PeopleAdapter
+import com.bedu.hilt.utils.Status
+import com.bedu.hilt.ui.people.viewmodel.PeopleViewModel
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class PeopleActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityRecyclerBinding
+
+ private val peopleViewModel : PeopleViewModel by viewModels()
+ private lateinit var adapter: PeopleAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = ActivityRecyclerBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ setupUI()
+ setupObserver()
+ }
+
+ private fun setupUI() {
+ binding.recyclerView.layoutManager = LinearLayoutManager(this)
+ adapter = PeopleAdapter(arrayListOf())
+ binding.recyclerView.addItemDecoration(
+ DividerItemDecoration(
+ binding.recyclerView.context,
+ (binding.recyclerView.layoutManager as LinearLayoutManager).orientation
+ )
+ )
+ binding.recyclerView.adapter = adapter
+ binding.swipeRefreshLayout.setOnRefreshListener {
+ peopleViewModel.onRefresh()
+ }
+ }
+
+ private fun setupObserver() {
+ peopleViewModel.people.observe(this, {
+ binding.swipeRefreshLayout.isRefreshing = false
+ when (it.status) {
+ Status.SUCCESS -> {
+ binding.progressBar.visibility = View.GONE
+ it.data?.let { people -> renderList(people) }
+ binding.recyclerView.visibility = View.VISIBLE
+ }
+ Status.LOADING -> {
+ binding.progressBar.visibility = View.VISIBLE
+ binding.recyclerView.visibility = View.GONE
+ }
+ Status.ERROR -> {
+ //Handle Error
+ binding.progressBar.visibility = View.GONE
+ Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
+ }
+ }
+ })
+ }
+
+ private fun renderList(people: List) {
+ adapter.addData(people)
+ adapter.notifyDataSetChanged()
+ }
+}
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/viewmodel/PeopleViewModel.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/viewmodel/PeopleViewModel.kt
new file mode 100644
index 0000000..7318c4f
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/ui/people/viewmodel/PeopleViewModel.kt
@@ -0,0 +1,42 @@
+package com.bedu.hilt.ui.people.viewmodel
+
+import androidx.lifecycle.*
+import com.bedu.hilt.data.model.People
+import com.bedu.hilt.data.repository.MainRepository
+import com.bedu.hilt.utils.NetworkHelper
+import com.bedu.hilt.utils.Resource
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class PeopleViewModel @Inject constructor(
+ private val mainRepository: MainRepository,
+ private val networkHelper: NetworkHelper
+) : ViewModel() {
+
+ private val _people = MutableLiveData>>()
+ val people: LiveData>>
+ get() = _people
+
+ init {
+ fetchUsers()
+ }
+
+ fun onRefresh() {
+ fetchUsers()
+ }
+
+ private fun fetchUsers() {
+ viewModelScope.launch {
+ _people.postValue(Resource.loading(null))
+ if (networkHelper.isNetworkConnected()) {
+ mainRepository.getPeople().let {
+ if (it.isSuccessful) {
+ _people.postValue(Resource.success(it.body()?.results))
+ } else _people.postValue(Resource.error(it.errorBody().toString(), null))
+ }
+ } else _people.postValue(Resource.error("No internet connection", null))
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/NetworkHelper.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/NetworkHelper.kt
new file mode 100644
index 0000000..6464adf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/NetworkHelper.kt
@@ -0,0 +1,44 @@
+package com.bedu.hilt.utils
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import android.os.Build
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class NetworkHelper @Inject constructor(@ApplicationContext private val context: Context) {
+
+ fun isNetworkConnected(): Boolean {
+ var result = false
+ val connectivityManager =
+ context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ val networkCapabilities = connectivityManager.activeNetwork ?: return false
+ val activeNetwork =
+ connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
+ result = when {
+ activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
+ activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
+ activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
+ else -> false
+ }
+ } else {
+ connectivityManager.run {
+ connectivityManager.activeNetworkInfo?.run {
+ result = when (type) {
+ ConnectivityManager.TYPE_WIFI -> true
+ ConnectivityManager.TYPE_MOBILE -> true
+ ConnectivityManager.TYPE_ETHERNET -> true
+ else -> false
+ }
+
+ }
+ }
+ }
+
+ return result
+ }
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Resource.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Resource.kt
new file mode 100644
index 0000000..e9839cf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Resource.kt
@@ -0,0 +1,21 @@
+package com.bedu.hilt.utils
+
+data class Resource(val status: Status, val data: T?, val message: String?) {
+
+ companion object {
+
+ fun success(data: T?): Resource {
+ return Resource(Status.SUCCESS, data, null)
+ }
+
+ fun error(msg: String, data: T?): Resource {
+ return Resource(Status.ERROR, data, msg)
+ }
+
+ fun loading(data: T?): Resource {
+ return Resource(Status.LOADING, data, null)
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Status.kt b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Status.kt
new file mode 100644
index 0000000..9687faf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/java/com/bedu/hilt/utils/Status.kt
@@ -0,0 +1,7 @@
+package com.bedu.hilt.utils
+
+enum class Status {
+ SUCCESS,
+ ERROR,
+ LOADING
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable/ic_launcher_background.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_main.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..64ac7ac
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_recycler.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_recycler.xml
new file mode 100644
index 0000000..c06dffd
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/activity_recycler.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/item_layout.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/item_layout.xml
new file mode 100644
index 0000000..741d66c
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/layout/item_layout.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/values-night/themes.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..439a65f
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/values/colors.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/values/strings.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..0f98279
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Dagger Hilt
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/main/res/values/themes.xml b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..2b19d3e
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/app/src/test/java/com/bedu/hilt/ExampleUnitTest.kt b/Sesion-03/Ejemplo-03/base/app/src/test/java/com/bedu/hilt/ExampleUnitTest.kt
new file mode 100644
index 0000000..5b0f4d1
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/app/src/test/java/com/bedu/hilt/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.bedu.hilt
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/build.gradle b/Sesion-03/Ejemplo-03/base/build.gradle
new file mode 100644
index 0000000..bae27d7
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ ext.kotlin_version = "1.5.10"
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.2.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.google.dagger:hilt-android-gradle-plugin:2.36"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/gradle.properties b/Sesion-03/Ejemplo-03/base/gradle.properties
new file mode 100644
index 0000000..2521752
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# 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
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.jar b/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.properties b/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fb16a81
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Jun 22 16:01:59 CDT 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/Sesion-03/Ejemplo-03/base/gradlew b/Sesion-03/Ejemplo-03/base/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/Sesion-03/Ejemplo-03/base/gradlew.bat b/Sesion-03/Ejemplo-03/base/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Sesion-03/Ejemplo-03/base/settings.gradle b/Sesion-03/Ejemplo-03/base/settings.gradle
new file mode 100644
index 0000000..1ae01ac
--- /dev/null
+++ b/Sesion-03/Ejemplo-03/base/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "hilt"
+include ':app'
diff --git a/Sesion-03/Postwork/README.md b/Sesion-03/Postwork/README.md
new file mode 100644
index 0000000..a6451b4
--- /dev/null
+++ b/Sesion-03/Postwork/README.md
@@ -0,0 +1,48 @@
+# Postwork 3 - Nueva API y definición de proyecto
+
+## Objetivo
+
+- Modificar un proyecto base de Android para implementar una API que aún no tiene agregada.
+- Definir las funciones generales del proyecto Android Avanzado.
+
+## Desarrollo
+
+En los ejemplos de esta sesión aprendimos la inyección de dependencias con y sin Dagger Hilt. Para el Postwork 03 queremos complementar lo aprendido.
+
+La inyección de dependencias le proporciona a tu app las siguientes ventajas:
+
+- **Reutilización de clases y desacoplamiento de dependencias.** Es más fácil cambiar las implementaciones de una dependencia. Se mejora la reutilización de código debido a la inversión del control, y las clases ya no controlan cómo se crean sus dependencias, sino que funcionan con cualquier configuración.
+
+- **Facildad de refactorización.** Las dependencias se convierten en una parte verificable de la superficie de la API, por lo que pueden verificarse durante el tiempo de creación de objetos o el tiempo de compilación, en lugar de ocultarse como detalles de implementación.
+
+- **Facilidad de prueba.** Una clase no administra sus dependencias, por lo que cuando la pruebas es posible pasar diferentes implementaciones para probar todos los casos diferentes.
+
+
+
+### Indicaciones generales:
+1. Modifica el proyecto base de la sesión para que implemente alguna API de tu preferencia. A continuación se comparten algunas API’s que puede implementar:
+ - REQ | RES --> [URL](https://reqres.in/)
+ - Pokémon API --> [URL](https://pokeapi.co/)
+ - Digimon API --> [URL](https://digimon-api.vercel.app/index.html)
+
+
+
+ > Nota: La URL base está declarada en el Gradle del proyecto.
+
+
+
+2. Ha llegado la hora de **seleccionar el proyecto con el que trabajarás** el resto de las sesiones, y que sería candidato a presentar como proyecto final. Para elegir te recomendamos darte el tiempo de pensarlo.
+
+ Hasta ahora sabes cómo trabajar con usuarios el **“Login** y registro” gracias a **Firebase Auth**, así como optimizar la gestión de errores con **Crashlytics**, y en esta sesión aprendiste cómo realizar la inyección de dependencias con **Dagger Hilt**.
+
+ Ten presentes los temas instruidos y los temas restantes del módulo, pues debes elegir algún proyecto en el que puedas implementarlos.
+
+ Existe la probabilidad de que en el proyecto no sea posible implementar todas las dependencias, ya que existe un límite de clases a emplear. Ahora puedes entender por qué algunas empresas tienen varias apps, como Facebook “Messenger” y Facebook “App”. No te preocupes por ese tema por ahora, pues hay una forma de actuar ante ese escenario. Ponemos a tu disposición la documentación que habla del multidex por si deseas echar un vistazo.
+
+ [Haz clic aquí para consultar la documentación de cómo habilitar multidex.](https://developer.android.com/studio/build/multidex?hl=es)
+
+
+
+[Regresar ](../README.md)(Sesión 03)
+
+[Siguiente ](../../Sesion-04/README.md)(Sesión 04)
\ No newline at end of file
diff --git a/Sesion-03/README.md b/Sesion-03/README.md
new file mode 100644
index 0000000..bce6a82
--- /dev/null
+++ b/Sesion-03/README.md
@@ -0,0 +1,44 @@
+
+# :wave: Sesión 03: Dependencias - Simplifica el código
+
+## 🎯 Objetivo de la sesión:
+
+- Formular el código de la app con dependencias manuales o desde Dagger Hilt para construir una app con una arquitectura sólida.
+
+## 🎯 Qué aprenderán
+
+- Creación de un proyecto Android con y sin la inyección de dependencias.
+- Implementación de diversas herramientas para inyección de dependencias.
+- Implementación de Dagger Hilt en proyecto de app Android.
+
+## ⚙ Requisitos
+
++ Revisión previa del Prework de la sesión.
++ Android Studio.
+
+## 🎩 Desarrollo
+
+En esta sesión aprenderemos la inyección de dependencias, o DI, técnica frecuente en programación y adecuada para el desarrollo de Android que es la base de una arquitectura sólida de apps.
+
+Al programar una app las clases suelen requerir referencias a otras clases. Por ejemplo, una clase Car podría necesitar una referencia a una clase Engine. A estas clases se les denomina dependencias. En el mismo ejemplo, la clase Car necesita una instancia de la clase Engine, de la que depende para ejecutarse.
+
+En ese sentido, una clase puede obtener un objeto que necesita mediante alguna de las siguientes tres maneras:
+1. La clase construye la dependencia que necesita. En el ejemplo anterior, Car crea e inicializa su propia instancia de Engine.
+2. La clase la toma de otro lugar. Algunas API de Android, como los métodos get de Context y getSystemService(), funcionan de esta forma.
+3. La clase la recibe como parámetro. La app puede proporcionar estas dependencias cuando se construye la clase, o pasarlas a las funciones que necesitan cada dependencia. En el ejemplo anterior, el constructor Car recibe Engine como parámetro.
+
+En general, implementar la inyección de dependencias suma las siguientes ventajas:
+- Reutilización de código.
+- Facilidad de refactorización.
+- Facilidad de prueba.
+
+
+
+## 📂 Organización de la clase
+
+- [Ejemplo 01: Dependencias manuales](./Ejemplo-01/README.md)
+- [Ejemplo 02: Implementar Dagger Hilt](./Ejemplo-02/README.md)
+ - [Reto 01: Agregar dependencias](./Reto-01/README.md)
+- [Ejemplo 03: Consumir API](./Ejemplo-03/README.md)
+ - [Reto 02: Nuevo módulo](./Reto-02/README.md)
+- [Postwork: Nueva API y definición de proyecto](./Postwork/README.md)
\ No newline at end of file
diff --git a/Sesion-03/Reto-01/README.md b/Sesion-03/Reto-01/README.md
new file mode 100644
index 0000000..087c4fd
--- /dev/null
+++ b/Sesion-03/Reto-01/README.md
@@ -0,0 +1,139 @@
+# Reto 01: Agregando dependencias
+
+## Objetivo
+
+* Formular el código de un proyecto Android con dependencias a nivel de Application y de Activity, y respetando el ciclo de vida.
+
+## Desarrollo
+
+En el ejemplo 2 se implementó la inyección de dependencias a nivel Application y Activity, y es momento de practicar lo aprendido. Para resolver el reto 1 sigue las instrucciones expuestas a continuación.
+
+1. Agrega una dependencia a nivel de **Application** que genere un número aleatorio entre 0 y 100. Imprímelo en el **onResume** del **MainActivity**.
+2. Agrega una dependencia a nivel de **Activity** que genere un número aleatorio entre 0 y 100. Imprímelo en el **onResume** del **MainActivity**.
+3. Crea otro **Activity** con el nombre **“OtherActivity”** y ábrelo desde un botón en el **MainActivity**. Después aplica las siguientes reglas al mismo:
+ - Al abrir el **OtherActivity** debe finalizarse el **MainActivity**.
+ - Sobreescribe el **onBackPressed** del nuevo **Activity**, provocando que abra el **MainActivity** y se finalice.
+4. Identifica y comenta el comportamiento con los números generados en los puntos 1 y 2.
+
+
+
+
+
+ Solución 1
+
+ AppModule
+
+ ```Kotlin
+ @Singleton
+ @Provides
+ @Named("randomNum")
+ fun provideRandomNum() = (0..100).random().toString()
+
+ MainActivity -> onResume
+
+ Log.e("MainActivity", randomNum)
+ ```
+
+
+
+
+
+
+ Solución 2
+
+ MainModule
+
+ ```Kotlin
+ @ActivityScoped
+ @Provides
+ @Named("randomNumAct")
+ fun provideRandomNumAct() = (0..100).random().toString()
+
+ MainActivity -> onResume
+
+ Log.e("MainActivityAct", randomNumAct)
+ ```
+
+
+
+
+
+ Solución 3
+
+activity_other.xml
+```xml
+
+
+
+
+```
+
+OtherActivity
+```kotlin
+import android.content.Intent
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+class OtherActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_other)
+ }
+
+ override fun onBackPressed() {
+ super.onBackPressed()
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
+ }
+}
+```
+
+MainActivity
+```Kotlin
+@Inject
+@Named("randomNum")
+lateinit var randomNum: String
+
+@Inject
+@Named("randomNumAct")
+lateinit var randomNumAct: String
+
+override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ findViewById
+
+
+
+
+ Solución 4
+
+
+
+La primera vez que se entra a MainActivity se generan los dos números, pero al estar navegando entre las dos Actividades se observa que sólo cambia el valor del MainModule, pues este depende del ciclo del Main, y como se está finalizando, eso hace que se genere de nuevo, y el del AppModule permanece con el valor de 21, ya que sólo se generará de nuevo cuando se finalice la app.
+
+
+
+
+
+
+[Siguiente ](../Ejemplo-03/README.md)(Ejemplo 3)
diff --git a/Sesion-03/Reto-01/assets/01.png b/Sesion-03/Reto-01/assets/01.png
new file mode 100644
index 0000000..25c03c8
Binary files /dev/null and b/Sesion-03/Reto-01/assets/01.png differ
diff --git a/Sesion-03/Reto-01/assets/README.md b/Sesion-03/Reto-01/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-03/Reto-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-03/Reto-02/README.md b/Sesion-03/Reto-02/README.md
new file mode 100644
index 0000000..3e26332
--- /dev/null
+++ b/Sesion-03/Reto-02/README.md
@@ -0,0 +1,117 @@
+# Reto 02: Nuevo módulo
+
+## Objetivo
+
+* Implementar un módulo faltante mediante la reutilización del código generado por Hilt.
+* Demostrar la imagen default en la lista de elementos.
+
+## Desarrollo
+
+Llegó el momento de agregar el módulo de **Planetas** a la app.
+Los requerimientos de este reto son los siguientes:
+
+1. Para hacerlo crea un nuevo **Activity** llamado **PlanetsActivity**. Este debe realizar la llamada al servicio de **Planets** y debe mostrar los resultados. Asimismo, mantén la estructura y utiliza la inyección de dependencias.
+2. Agrega el nuevo módulo **Planets**. El usuario debe tener a su disposición la opción de elegir **People** o **Planets**. Al hacer clic sobre alguna de ellas deben realizarse las llamadas e importaciones necesarias para consultar el API y mostrar la lista de resultados. Además, la lista debe tener habilitado el **swipeRefresh**.
+3. Una vez que hayas implementado el servicio, crea una dependencia que contenga una imagen de Star Wars; puedes agregar el **base64** o la URL. Inyecta esta imagen y después debes asignarla a la lista para que todos los elementos muestren esa imagen.
+
+
+
+Las propuestas de solución son:
+
+
+
+
+
+
+
+
+
+ Solución 1 - 2
+
+Agregar **ResponsePlanetModel** con los datos del **Json**.
+Nueva función a **ApiHelper**.
+
+```Kotlin
+suspend fun getPlanets(): Response
+```
+
+**ApiService**
+
+```Kotlin
+@GET("planets")
+suspend fun getPlanets(): Response
+```
+
+Override a **ApiHelperImpl**
+
+```Kotlin
+override suspend fun getPlanets(): Response = apiService.getPlanets()
+```
+
+MainRepository
+
+```Kotlin
+suspend fun getPlanets() = apiHelper.getPlanets()
+```
+
+Copiar paquete **main.people** a **main.planets** y modificar las referencias de **People** por **Planets**.
+
+
+
+
+
+
+ Solución 3
+
+**ApplicationModule**
+
+```Kotlin
+@Singleton
+@Provides
+@Named("provideImage")
+fun provideImage() = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASEAAACuCAMAAABOUkuQAAAAnFBMVEUAAAD/6B//8CD/6h//7SD/7CD/8SCtnhXdyRvt2B313x5kWwyJfBH/8yC/rheMfxHn0hx4bQ8UEgKThRLEsxhVTgogHQSajBNORwpnXg2omBT75B/UwRpwZg5eVQu6qRfizhsqJwWAdRAKCQExLAYcGgPMuhltYw3YxBrDsRg3Mgd2aw5DPQiXiRIYFgM7NgcmIwVQSQr/+iFHQQkuOprKAAAUNElEQVR4nO1daVfqwLLN0B0GTxQERAgCggIqiMP//2+3KoEk1VUdEsD73lo3e50PRzLvdFfXHMepUaNGjRo1atSoUaNGjRo1atSoUaNGjRo1atSoUaNGjRo1atSo8b+Il22CxwyDDNMTuMkwirH++r9+oKti0W+HAYd3AX5u0rNv2la4j5Y7sh/SbrVanU5n3mxOVm+zcff1v8DP0PW0754JX4TretPj6V88eR+EaljuyX7IERqhlBfOe3/Mz6Dt+a5WnmXwqAxaAqEl4y3H0FC5Wh5nyvUjy13BGZRteOZvCK7qe+7wLwm6C4CfoDmcvr9keM7wleE1xed9imWG3Fl9P2Oo4+vN4p8E4C6YCvcUM6TG4jF3gF5vNxyOG7Pbt1VHexo4am3/jKBd6LrB5vfap80xtPdc78OyW9tXM3mLm6O4GB+TQMMg7Va9xZLohnAr/65/3hxDY+Vr224NZZtmcFs38haObTNw/fCu0g2WxYsCYTn4gxPnGGr5+s2222/gBmtxSxWGHKcHoiK0DdSLMNduUOFGyiNj6Dd0g5F1Pyt91RhyRrBeqj+QRTDHvPH1T+vkGbJPJARMQVfcUJEhZwTiol3lgHJo+X7r+mdFZAy1fW0Rxoj30CLGqzLk7ALXsylXZ2MKE+Dp2idNkDI0CN2QLkr0L1AFVtIJKjPkTLTrXdvSmem/GJgxUoZmyrxG6zn/19Cy0lVn6EuBClXtkJNoX/+UR6QMRaZh8f5DFOAvmGYL4QTVGfqDF/7luWW1sso4MnQDy/k32TL2OuTvptYT4QScoYYfJUDjtTNfMWvsxnPD65qxA89V8sRdLhOL4hPx+pACTQ+654OI19cjQ7faXAvafvCe/7sHd3HPb0FgSFHD1XONsXcPgsiuV5yDtSeutNO5izYzIrYTgzAPYxxHoYjgaLn65kSeBi795RNGsqAOSwzBb5nxqrkaDVLjumb+h8jQvtATYo6IlnXfmKEneHyqx820eY6N1k1+G+IY6nwsEvzrjSdgaRgyfn5tuSqPoRn3VaROESUxpATXGyD2oPXZJHPRdUQM5X8gPh7YbUgMUSanwD41V1fa6m46D9+gY+3ZryA5V4PRaJQ4V2MP7Hfskt1u97A0M4bU+PdRwjcKTe0r6rr58GB4GW8adtqx2zjNEKhSxsmBoQLl9Bwo8xIIHEMvlgPuJIYKbOouvGZ6rpV22TRbaZ8ub4gSDDW1QXXz2mMIb40rEC+eq22mSFWG4AJz8sMS9MO+NhQA4DFk7+Q0Q8+wdFHB3JYG40UAq0MgfQiTzzJYKzK01ObicgeDiiuRbMFzLJK6tUj9jL1hBOslUc+f4eTXdlSAKSN4QZvaDSU1tzJDIIMDqsKBkNtwQ4TL8xKrvfLdkPIK9AfWezkTX+gIZ0rjZwT6nuhrqcgQW8efAzQxwJgNiNduDY9mXu+kxujr0Bjpc1/Uzi9DN5SEzsDma6nG0KsydcGDmcq80y6PCnGGxiRkBmaH4Za4AeL/wFndAJ1/w37dgeIrvY5qDPVQ6Bh7x64O5lQTbM7qlmvL/xtPxQRe9C37daXcQFBPqzHEbNJtmHilH0ND/KF9a3jLKzN0q9zwb+IdLZDWXCsCXVmQ4ZUYwqWFCvx07LRMv2PEokJVGRqG0mS4CkAuC0vXO4hF99P8tRJD3DeWyp8xm2bMz1aRoTGIzkhwEVwFeyCD3w3KcGZQVmKI+VfBrPcSVXHrGSGWb3PeVWNoOfHAjP27sCsojr5mBtoMJok5+6owxH30II+j0RNi3fY1FX7M31+FoTsfbBltyyK5BhahlGEAAio0otVVGOJxHtdPVT74n1u8d3mGpi04naLe76tjKK3uKIoMPqowxGKFTwFR+GiY8bjMpSjN0CREf8qVbXqOWz5eEiOKWoIVGOKh1pkb5eHShwJC+/m/OUNd2cMKi5irzlzmp727ssA0FR6+b5r2UgWGikOtHLDy+fm/BYZCmaLbAKbsbNZojMfD4XDXw6f+t1h0n9aj6RR9W/aLNkJVGi69vwQjGETE616BIXvei4z3gHoMOUMfniXJZoYrTf5hqH/0xy6hxsqWQyekvImZE8rwc5ZnaBBYc6csmFPlQGLIt7gchmFRQhwNrRAAQ1GrJDriWGwZ/p3yDHEV8BR2ilhxEkOua0kSGk0mm82m2WzO551Oq9VuR2ALH/IAudsgw1jpC/XwueGmLc8Q85KdBMY3c6lenKEndHGHFTMWwfQJ7IJobDp2K+PsMcRDracRe9dSyAwxr9kpoHFozyC7nCFlqMWlGbo9I4SOLsLMshIZQkUzqLQAPKiiyPvFDH17RrioNEPuGbG9T5X3zHOG1riyggT2+k55fOo/ZWhsituyDMHDhDwSdwoTrefpHyJDobOP4JEr+FqXklWe4mKGmE5TliHJNX8aCy8XvLAw5Hy1tavm5U9aaL1cyhDcsaFol2XIN0OV/c1kMlkl6APe3t5uEfTYfISWP9koZsj5BItatUq7guA8crIt4lKGIj836mOUZIiFCL9CseBBK2qY5IOvVoZAB1GubtvCwvwhPHsi4oUMrZSZgViWIRZq7YFVI5WEuCFRCT5yK0MBQ87Gc7VbMgscGLLnWV/G0NhzlblqlGRImdHhDQyO2QG3CXCeReaKp7MfOEM3KUNOH4xVMbePAxiyG/4XMTQLYCibP5Zj6B8MBZLusmQ+/QQsQS0n4QsZit3SYSmlPSqi8gKGBi209pnJV44hFmrFRUpKMMTViRjeoyC1EYoZiiuavObSOYmoqGzlTLvsftBrhr6rI27xlWLoPjBHzErMMnPiNY9mPmTmHDBkSJpBniFnGvumdyd9r4WZexhzaZYCmsQIMItdL/QwRzDYsFgQMuQaZ4xcxlAPrAO6k+taslZQpHeTvLsu4mmSWiswhDvGTfp5hpznFlxHhV7Ujos6O3MEfzTrtROGxBWkuM4Q/Sq+9iJx8gJDLj3S5Qw1tWtc1+qjAYnl591dHuwaDg4MmTcPdxaSoxsh/sYrO80btLsDqvgYc965IIwmlqnbE84YGoP45Uc4rUXDfuAVsO5BjRdv74ce/rjSoVFoKqDAG/DUKIsxAn28d4vu+teetT2VDp6W2Me24E6OyRyJc9/HPOXEHSzeJzfrt+vu4q43HMZPMJafzq5T16hxMda7HkFcZpxtXvQYdlnQ7HfEsc4MxsPqJ0GshkLcl0EJHeeI9+4w1dHt6Bf4YRaSYE2DTsuAi7gwC5O2QlbnnitZGIT2uElgU1LmcokDhRd1bhclaBrM2qFn6QFAEBYF9H1zNQRRmHJw57FYUS6avg15IULOisKsa3np0PbldaPLNYHQnl6dMEwHzVD5rrS8s9U+KCqV78MOnXzQp+1nkcOm9iOysdMCTf4o+Mdm8QJGxzMtO/L1ZCih15Tyx1OGLM0baEsGUFh1sLGHuTCICPuoQHcm/bd+Ad5WupihdWCmHGeRTZ4iFqf8HM15lr9CzMyRZ70wL3ZJAQbbW74fjYib7jgeH5rl5uTuEzXNaFwimvIQFDPEPepZRu1QmXmY+eYBPOWJ+A152RjZ0aKjbcrWXdwPIw+mh80f3cLSh3JtFN6DooiiIzxJTx3r3aQS3H1absNipl0vbzoUxTLs7JVmyEkSipQ8XTfwDGXMesRJhm4CI+vlPjzkOG8DqYw7pY3FTEl5CsykwLqG2qOJVRhy9i0lU9QLKuR0nmSIP+nk4ImQWwEcszP5U5ISp1VhLMMaka7EECwlSsrqXvpVmgScZojNlsWhoKllSuIYLwfxzWbKgpTJsVhG8TWPAEldKWAKFPFEZlhkeTKYFchQceRuKg2GoSSJExxyVJicmeSdYEgXrQYhTteB5dyVGYqzus1FPzKS1YpxmiH0sTGB0rK/557ylbBi35OIMQmOIpYnEluz46oxtIdJb3gn4ZUXKskGSjDUMKkAHSncWmXFQ+xCZTFTTGlMbbKlMj2b/2hqua3dSWWGnKFnRqRYpLwYJRjiyWAYg5kGtrSauBiDyZlNPnMFy8aoi7YZEq+7rasQZ+h1u39/x/Zi2EzsVVjB22ZF1EpL8tOKEgzx4DtMsNbMuhihtYbhaBLTfCDZT4QuxFeoihNbD+AMLX6OpdVos/pRyxzYmJlGPHqdalklyFCR+YJgSakwqtDZabsObI18FjP1VfqCX2mymBPrCJH5gxJOPWHvPy6dzjcu9NrUMbA0L9aqVsv6VYKhx8BsU9VGb71QR55gorHRH5Uz83wdFLahoPMBlxxyiXdWCn84tcCQD8MnbXGoWUFg0zhGZmi7wTzGDcEEAcbySYa4DRrnyM5tuy/idEFCwTPp7zI3y8bgHbjGJeZiVyHOUNfzfef5+eXlfb/9HdysV8pMcm8oum7Ks6xj9RMV5sIewEqVtsCBZw+zabCrKQUkG/yZtcOZIeP0Ej3BLLYylMfGVCR6xtolSuo9viNrrOMkQ6xkAt6DEVgn6GuTAmLkmsnzuDhieiFJmH9gsgpRgqGFZyzm/zxKvrjaw9Ks+2OCXIDE/qhHsJVlVxiuvgmMyjmsg8pycJhPYA2ypG2WuTTN9Q7B3z9jaGgSYDbSmLKuYYCle1lDN6bAPXiFTSrbilJAjt8TuhBo9e/MS7D8j2RPk6GF0Zxl6pr8wzH0B3gZnPsF2PvWAMJp8IfaFFbuj0M6KUkdFNeX0dB7CV0jGc4TRB08rdF8EZYFf3U7w7kwm/VXHSAspB5q31y7dqBmc3UUS5cv6GjBJsbCcCpQPe2FTjKqITOfQNIcp2POZJaH5lgYSttBxaF530i675rFNziIJJumLZYulwWvyaW+sw9D9NIqJaJyonZFNycSh11iwR9NYOguJPEcxTIqhLjAWqrAdfaYAnB2s0GzMsnEisu+HIilzjT09yRbiOuIQuseztDLv2HjbbWaxJmy/dnY9Hpi8TATmbdKqkmU20+UhazApfCKXH/U9GVW3tH5z2Zyn799ztApwIwS6vg6WuqXgO0nzpbWYP9JdtIBd15ROSEZNVPWXKF9EEBD8xJr7v+szNBEiV1s4hYB3Mm5UZVLh1JIsbEMc9OsIiCjhjne0J8YH/vCLsHjIVUZWnly+xFn70tdFFBah+XKhzksbSFjgEJomlU5oE8vc+Myx1tWBNQ0pxmvD6rIEGaWWyTLI3YfYsJzq86X1ryNS4bYkJVbIDtGWxcWXAJlyN/0doDeShvTjHKLAIbKu5gHEVYn2LZOYenSzOBCaW0LiZ8AllnZ1Og2mlXW1H4yaqQQCEymQ0aDOc2YVK/A0OttCDc1t++wEHskgbQ+twWzaCfFmMYuM9utj8ioYaJlQ/pKGYE+phmUZmjZwOrtsNDdOhZ7JM21qZSXxR0IPSH910nGRc/a7P8tP2qezLKxT6PSuE0u8W367vqMIUv9SgMGkN8+0WYADQ0mrT/hRZ03z+7l7qtOMi4erColGTVi48QCmBYKZ2hqETQdGELzx+2z/FJjLJ957ZKTGEHnrWcTS158Nx4XNpWSjhrWofMExoYrSWAobMtrTydunKcKcsywmZ70SKz7U1ksLK2WJ/G42Ik+QWPUHAPapbE1vmUiMORpV3aYNz0/7+E3k+WS30NhfRmzyoqykNwRSb+7Hit2T0GMKxZqPQnDFJEYgseXE0XGkfaKvn6FfXyleA1MigL7oQgr8fl2QA167eW1jo4ameMiGBa/yBBIOovdfL///R5Mpzej9Xr9RLAe3Uy/f+X5+RgYxQ2lIc+R41smYecUxMkDMlCddvkSGKaIzFBhJWp1bIGhMxuiSZ2Et8dWXDR1IT0kHzhjodYSoJEjztANMAQy+ZqdJkkZWjVIXr9G6lOVhAw6m9OhzEOtJUCb4L8JDPkuaMe2PrTnoFex8VEOuK6blkzmHSPF7geQYkPMgKyQL58Aq/EyNYwzhJ/7cbr4WaSrNbhfnTHUj+CZY2hcHnV0Pglpj//z+tISNYzPspihuB19xY4ndlRV2vLgXr+8TcEVZiK9mf9nvZkc+gvEzQWOpdCNGVkOyNDkY2idxMumqmrHEyuwX1klpS0PZlY5+e/I5IvdExCnEnPV9z1BzcUgMA3KqFwRg5Uh51sDRVU6nljhXtSC2TTNaTxCG1upY5L5obFcjhsFzBLIrw+coadjzDXueHJhL6D4cqp646Mc3gz3Dk0jMFPziCViGhDxl0nSDgNYW7GKQxb4yTiijXRzA7eAoaTjSevSj9pgY8mKwQKCUZzCmOKBLDSGK8gIkLCPIbL8yAOYqy5XxHBbwJCzBGNVWz+AWw67iz/zRt3Mw3xmGdtKI2As1NqydBNkHvHcwOUMfeQzG7D9bXDJ9yKx7eCFnwqkvcRbhmihW4lofgyNdmKYRSQ2kGTOODAsjkOTM0RzP2b45dRVgU+oEAOsGLLZeGVxgyHMgxW4XijDO42JJ5mUI5H4BsyAWbymJ5XVQxBaQotLJ5bvarj++Pg4dBpYLNz0kxeFswxxh18n1o314/795et1WUZBXX5+vey/n3qzFn6598JZ6sTJUGnHS/7JYswZSPu2Eu8+pj5mC3rst7dFcTvG544xknIYmrdYo0iaw0Y+JfqxrbCTYpzVqGM3UFQM7OaJOyvMigia546/DJhQl6vKNCQJfhFDquiE0WUu6r4fWIy0oeKer0NoCxlidaPGUJwFyrc6ziQc9gWiomt883b6ky+6/THG5PcPqfvNls0F9gtK1vPNoVHI3NYQeptcAseZfxwFbjLN+ry4GGAc/z5rxcmxJco9U19aGLY3jT/5Lq2Jj24Oi+rd8E4gLlBfw7+n9dPHxxNeDeSUtOfX/hF9ZzejeGfc+4PcGwBOAJtuptPB7982765Ro0aNGjVq1KhRo0aNGjVq1KhRo0aNGjVq1KhRo0aNGjVq1Kjx/wX/AWRjlaZeFgC1AAAAAElFTkSuQmCC"
+```
+
+Modificar en **PeopleAdapter** y en **PlanetsAdapter** para que reciban el **imagePath** en el constructor y lo envíen como parámetro a cada elemento.
+
+```Kotlin
+class PlanetsAdapter(
+ private val planet: ArrayList,
+ private val imagePath: String
+) : RecyclerView.Adapter() {
+
+…
+
+fun bind(model: Planet, imagePath: String) {
+ itemView.textViewUserName.text = model.name
+ itemView.textViewUserEmail.text = model.population
+ Glide.with(itemView.imageViewAvatar.context)
+ .load(imagePath)
+ .into(itemView.imageViewAvatar)
+}
+
+…
+
+holder.bind(planet[position], imagePath)
+```
+
+Inyectar dependencia en **PlanetsActivity** y en **PeopleActivity**.
+
+```Kotlin
+@Inject
+@Named("provideImage")
+lateinit var provideImage: String
+```
+
+Enviar dependencia inyectada al inicializar el constructor.
+
+```Kotlin
+adapter = PeopleAdapter(arrayListOf(), provideImage)
+adapter = PlanetsAdapter(arrayListOf(), provideImage)
+```
+
+
+
+
+
+[Siguiente ](../Postwork/README.md)(Postwork)
\ No newline at end of file
diff --git a/Sesion-03/Reto-02/assets/01.png b/Sesion-03/Reto-02/assets/01.png
new file mode 100644
index 0000000..a237d4f
Binary files /dev/null and b/Sesion-03/Reto-02/assets/01.png differ
diff --git a/Sesion-03/Reto-02/assets/02.png b/Sesion-03/Reto-02/assets/02.png
new file mode 100644
index 0000000..d7ad10d
Binary files /dev/null and b/Sesion-03/Reto-02/assets/02.png differ
diff --git a/Sesion-03/Reto-02/assets/README.md b/Sesion-03/Reto-02/assets/README.md
new file mode 100644
index 0000000..1ec96c5
--- /dev/null
+++ b/Sesion-03/Reto-02/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el reto
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/README.md b/Sesion-04/Ejemplo-01/README.md
new file mode 100644
index 0000000..d54cd94
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/README.md
@@ -0,0 +1,74 @@
+# Ejemplo 01: Gráfico de navegación
+
+## Objetivo
+
+* Implementar el gráfico de navegación mediante su descripción de funciones e interfaz para usarlo desde Android Studio.
+
+## Desarrollo
+
+A partir de un proyecto de Android previamente creado, se revisarán las herramientas de navegación introducidas con Android Jetpack Navigation. Usaremos el [Proyecto base](./base) y le modificaremos lo que se requiera.
+
+Para hacerlo realiza los siguientes pasos:
+
+1. Ejecutamos el proyecto base con Android Studio. Este desplegará la siguiente interfaz.
+
+
+
+2. Nos dirigimos a los recursos del proyecto base y abrimos el mobile_navigation.xml
+
+
+
+ Este recurso define todas las rutas posibles que nuestro usuario puede tomar dentro de nuestra app.
+
+ > Nota: Las flechas entre los destinos se denominan Acciones, y las vistas previas Destinos.
+
+
+
+3. Android studio nos presenta tres opciones de visualización, “Como en cualquier XML”.
+
+
+
+4. En el modo Design haz clic en la pantalla Step one, lo que despliega la opción Attributes.
+
+
+
+ En esta sección se especifican los argumentos / parámetros que recibe la vista, así como a qué destino es posible navegar. En esta pantalla vemos que recibe un **integer** y el destino es **Step Two**.
+
+
+
+ Ten presente que:
+ - **\** es el nodo raíz de cada gráfico de navegación.
+ - **\** contiene uno o más destinos, representados con elementos **\** o **\**.
+ - **app:startDestination** es un atributo que especifica el destino que se inicia de forma predeterminada cuando el usuario abre la app por primera vez.
+
+
+
+ Ahora veamos un destino de fragmento.
+
+ ```xml
+
+
+
+
+
+ ```
+
+ Revisemos algunas de las etiquetas del XML presentado anteriormente:
+
+ - **android:id** define un ID para el fragmento, que puedes usar en otra parte del archivo XML y de tu código para hacer referencia al destino.
+ - **android:name** declara el nombre de clase completamente calificado del fragmento para crear una instancia cuando navegas a ese destino.
+ - **tools:layout** especifica cuál es el diseño que se debe mostrar en el editor gráfico.
+
+
+
+
+
+[Siguiente ](../Ejemplo-02/README.md)(Ejemplo 2)
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/assets/01.png b/Sesion-04/Ejemplo-01/assets/01.png
new file mode 100644
index 0000000..e735d8a
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/01.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/02.png b/Sesion-04/Ejemplo-01/assets/02.png
new file mode 100644
index 0000000..6a50374
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/02.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/03 (1).png b/Sesion-04/Ejemplo-01/assets/03 (1).png
new file mode 100644
index 0000000..f0f45e0
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/03 (1).png differ
diff --git a/Sesion-04/Ejemplo-01/assets/03.png b/Sesion-04/Ejemplo-01/assets/03.png
new file mode 100644
index 0000000..59086e6
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/03.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/04.png b/Sesion-04/Ejemplo-01/assets/04.png
new file mode 100644
index 0000000..142d770
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/04.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/05.png b/Sesion-04/Ejemplo-01/assets/05.png
new file mode 100644
index 0000000..fe07aaa
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/05.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/06.png b/Sesion-04/Ejemplo-01/assets/06.png
new file mode 100644
index 0000000..4112ff4
Binary files /dev/null and b/Sesion-04/Ejemplo-01/assets/06.png differ
diff --git a/Sesion-04/Ejemplo-01/assets/README.md b/Sesion-04/Ejemplo-01/assets/README.md
new file mode 100644
index 0000000..a46b26b
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/assets/README.md
@@ -0,0 +1 @@
+## Aquí puedes sustituir este archivo por imagenes o código que requiera el ejemplo
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/base/.gitignore b/Sesion-04/Ejemplo-01/base/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/Sesion-04/Ejemplo-01/base/app/.gitignore b/Sesion-04/Ejemplo-01/base/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/base/app/build.gradle b/Sesion-04/Ejemplo-01/base/app/build.gradle
new file mode 100644
index 0000000..ac1d0c9
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/build.gradle
@@ -0,0 +1,49 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ applicationId "com.bedu.navigation"
+ minSdkVersion 19
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation 'androidx.core:core-ktx:1.5.0'
+ implementation 'androidx.appcompat:appcompat:1.3.0'
+ implementation 'com.google.android.material:material:1.3.0'
+
+ //Navigation
+ implementation "androidx.navigation:navigation-fragment-ktx:2.3.5"
+ implementation "androidx.navigation:navigation-ui-ktx:2.3.5"
+
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/base/app/proguard-rules.pro b/Sesion-04/Ejemplo-01/base/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/base/app/src/androidTest/java/com/bedu/navigation/ExampleInstrumentedTest.kt b/Sesion-04/Ejemplo-01/base/app/src/androidTest/java/com/bedu/navigation/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..acb853f
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/src/androidTest/java/com/bedu/navigation/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.bedu.navigation
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.bedu.navigation", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/Sesion-04/Ejemplo-01/base/app/src/main/AndroidManifest.xml b/Sesion-04/Ejemplo-01/base/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e1f9809
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/src/main/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Sesion-04/Ejemplo-01/base/app/src/main/java/com/bedu/navigation/DeepLinkFragment.kt b/Sesion-04/Ejemplo-01/base/app/src/main/java/com/bedu/navigation/DeepLinkFragment.kt
new file mode 100644
index 0000000..2a77f24
--- /dev/null
+++ b/Sesion-04/Ejemplo-01/base/app/src/main/java/com/bedu/navigation/DeepLinkFragment.kt
@@ -0,0 +1,31 @@
+package com.bedu.navigation
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+
+class DeepLinkFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.deeplink_fragment, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val textView = view.findViewById(R.id.text)
+ textView.text = arguments?.getString("myarg")
+
+ val notificationButton = view.findViewById