diff --git a/README.md b/README.md
index bd73feb5f..654583031 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,44 @@
+# Teste - Accenture
+Projeto de teste para seleção da empresa Accenture para o cargo de Desenvolvedor Mobile Android
+
+# Procedimentos para execução do projeto
+O projeto android encontra-se na pasta "TesteAndroid".
+Para execução do projeto é necessário abrí-lo na IDE Android Studio.
+
+# Procedimentos para execução dos testes unitários
+Foi implementada uma classe para realização de todos os testes unitários do sistema
+em 'com.accenture.android.app.testeandroid.TestSuite'.
+
+Basta executar esta classe e todos os testes implementados serão processados.
+
+# Implementação
+Como forma de implementação da solicitação de exibição na tela de login do último usuário salvo, foi utilizado o componente nativo da SDK do Android “SharedPreferences”.
+Para exibição do último usuário salvo no sistema, foi definida na tela de Login uma pequena descrição com o nome do usuário, sendo esse buscado do SharedPreferences do smartphone. Segue exemplo:
+
+
+
+Obs.: Caso o usuário vá para a segunda tela do aplicativo onde ele clique no botão de logout  , ele retornará para a tela de login e o nome do usuário não será apresentado, pois os dados do usuário são apagados do sistema. Para que essa descrição com o nome seja visualizada, é necessário efetuar o login ao menos uma vez no aplicativo, sair sem se deslogar (Fechar o aplicativo) e entrar novamente.
+No meu entendimento, este desafio seria para testar a utilização de autenticação e a forma de guardar dados no smartphone para posterior processamento. Sendo assim, a implementação foi feita pensando em um caso de uso real, onde se o usuário não fizesse o logout, quando ele abrisse o aplicativo novamente e fosse para a tela de login já haveria dados pré-cadastrados no sistema e a autenticação seria feita de forma automática. Porém, para exemplificar, apresento apenas o nome do usuário na tela.
+
+## Arquitetura
+Para confecção do aplicativo foi utilizado a arquitetura MVP (Model View Presenter).
+Essa arquitetura foi escolhida por ser um padrão amplamente utilizado em desenvolvimento mobile, com fácil entendimento e uma boa separação de responsabilidades.
+
+Definição rápida dos diretórios criados:
+* data: Contém todo o código referente a dados do sistema (Gerenciamento de consumo de APIs e conversores de dados)
+* domain: Contém as classes de domínio. Nossas models, por assim dizer.
+* helpers: Contém classes que irão ajudar no desenvolvimento do sistema que podem ser reutilizadas em qualquer local e que não possuem nenhuma dependência com componentes do SDK do Android (Soma, subtração, formatação de strings, etc...).
+* presentation: Contém toda a lógica de cada tela, junto com seus respectivos presenters.
+* utils: Contém classes que são um pouco mais complexas ou elaboradas que podem ser reutilizadas em qualquer local, porém possuem uma dependência do SDK do Android (SharedPreferences, por exemplo).
+
+## Teste unitários
+Para os testes unitários foi utilizado o JUnit por ser nativo do Java e possuir uma quantidade grande de ferramentas para serem utilizadas.
+
+## Outras bibliotecas
+Para consumo das APIs foi utilizado o framework Retrofit2. Esse framework abstrai uma boa parte da lógica de acessos HTTP e ajuda no gerenciamento das rotas que serão utilizadas.
+
+Para listagem dos 'statements' foi utilizada a biblioteca RecyclerView.
+
# Show me the code
Esse repositório contem todo o material necessário para realizar o teste:
diff --git a/TesteAndroid/.gitignore b/TesteAndroid/.gitignore
new file mode 100644
index 000000000..603b14077
--- /dev/null
+++ b/TesteAndroid/.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
diff --git a/TesteAndroid/.idea/codeStyles/Project.xml b/TesteAndroid/.idea/codeStyles/Project.xml
new file mode 100644
index 000000000..fb22c1d7e
--- /dev/null
+++ b/TesteAndroid/.idea/codeStyles/Project.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/dbnavigator.xml b/TesteAndroid/.idea/dbnavigator.xml
new file mode 100644
index 000000000..51325a2a9
--- /dev/null
+++ b/TesteAndroid/.idea/dbnavigator.xml
@@ -0,0 +1,458 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/gradle.xml b/TesteAndroid/.idea/gradle.xml
new file mode 100644
index 000000000..ac6b0aec6
--- /dev/null
+++ b/TesteAndroid/.idea/gradle.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/jarRepositories.xml b/TesteAndroid/.idea/jarRepositories.xml
new file mode 100644
index 000000000..a5f05cd8c
--- /dev/null
+++ b/TesteAndroid/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/misc.xml b/TesteAndroid/.idea/misc.xml
new file mode 100644
index 000000000..37a750962
--- /dev/null
+++ b/TesteAndroid/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/runConfigurations.xml b/TesteAndroid/.idea/runConfigurations.xml
new file mode 100644
index 000000000..7f68460d8
--- /dev/null
+++ b/TesteAndroid/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/.idea/vcs.xml b/TesteAndroid/.idea/vcs.xml
new file mode 100644
index 000000000..6c0b86358
--- /dev/null
+++ b/TesteAndroid/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/.gitignore b/TesteAndroid/app/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/TesteAndroid/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/TesteAndroid/app/build.gradle b/TesteAndroid/app/build.gradle
new file mode 100644
index 000000000..0bf5a6132
--- /dev/null
+++ b/TesteAndroid/app/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+
+ defaultConfig {
+ applicationId "com.accenture.android.app.testeandroid"
+ minSdkVersion 19
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation 'com.fasterxml.jackson.core:jackson-databind:2.10.2'
+ implementation 'com.google.android.material:material:1.3.0-alpha01'
+ implementation 'com.squareup.retrofit2:retrofit:2.6.4'
+ implementation 'com.squareup.retrofit2:converter-gson:2.6.4'
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/proguard-rules.pro b/TesteAndroid/app/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/TesteAndroid/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/TesteAndroid/app/src/androidTest/java/com/accenture/android/app/testeandroid/ExampleInstrumentedTest.java b/TesteAndroid/app/src/androidTest/java/com/accenture/android/app/testeandroid/ExampleInstrumentedTest.java
new file mode 100644
index 000000000..4c4bb9b41
--- /dev/null
+++ b/TesteAndroid/app/src/androidTest/java/com/accenture/android/app/testeandroid/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.accenture.android.app.testeandroid;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.accenture.android.app.testeandroid", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/AndroidManifest.xml b/TesteAndroid/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..20b63cac6
--- /dev/null
+++ b/TesteAndroid/app/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/App.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/App.java
new file mode 100644
index 000000000..5e347e809
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/App.java
@@ -0,0 +1,19 @@
+package com.accenture.android.app.testeandroid;
+
+import android.app.Application;
+import android.util.Log;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class App extends Application {
+ private final static String TAG = "CustomLog - " + App.class.getSimpleName();
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Log.i(TAG, "Application started.");
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/StatementConverter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/StatementConverter.java
new file mode 100644
index 000000000..70f16f8e7
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/StatementConverter.java
@@ -0,0 +1,36 @@
+package com.accenture.android.app.testeandroid.data.converters;
+
+import com.accenture.android.app.testeandroid.data.http.responses.StatementResponse;
+import com.accenture.android.app.testeandroid.domain.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatementConverter {
+ public static Statement toDomain(StatementResponse.StatementData statementDataResponse) {
+ Statement statement = new Statement();
+
+ statement.setTitle(statementDataResponse.getTitle() == null ? "" : statementDataResponse.getTitle());
+ statement.setDesc(statementDataResponse.getDesc() == null ? "" : statementDataResponse.getDesc());
+ statement.setDate(statementDataResponse.getDate() == null ? "" : statementDataResponse.getDate());
+ statement.setValue(statementDataResponse.getValue() == null ? 0 : statementDataResponse.getValue());
+
+ return statement;
+ }
+
+ public static ArrayList toDomain(List statementDataResponses) {
+ ArrayList statements = new ArrayList<>();
+
+ for (StatementResponse.StatementData statementDataResponse : statementDataResponses) {
+ Statement statement = StatementConverter.toDomain(statementDataResponse);
+
+ statements.add(statement);
+ }
+
+ return statements;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/UserAccountConverter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/UserAccountConverter.java
new file mode 100644
index 000000000..5bc6e1e66
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/converters/UserAccountConverter.java
@@ -0,0 +1,22 @@
+package com.accenture.android.app.testeandroid.data.converters;
+
+import com.accenture.android.app.testeandroid.data.http.responses.UserAccountResponse;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class UserAccountConverter {
+ public static UserAccount toDomain(UserAccountResponse.UserAccountData userAccountDataResponse) {
+ UserAccount userAccount = new UserAccount();
+
+ userAccount.setUserId(userAccountDataResponse.getUserId() == null ? 0L : userAccountDataResponse.getUserId());
+ userAccount.setName(userAccountDataResponse.getName() == null ? "" : userAccountDataResponse.getName());
+ userAccount.setBankAccount(userAccountDataResponse.getBankAccount() == null ? "" : userAccountDataResponse.getBankAccount());
+ userAccount.setAgency(userAccountDataResponse.getAgency() == null ? "" : userAccountDataResponse.getAgency());
+ userAccount.setBalance(userAccountDataResponse.getBalance() == null ? 0 : userAccountDataResponse.getBalance());
+
+ return userAccount;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/RetrofitConfig.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/RetrofitConfig.java
new file mode 100644
index 000000000..ffc6a0249
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/RetrofitConfig.java
@@ -0,0 +1,40 @@
+package com.accenture.android.app.testeandroid.data.http;
+
+import com.accenture.android.app.testeandroid.data.http.resources.AuthResource;
+import com.accenture.android.app.testeandroid.data.http.resources.StatementResource;
+
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class RetrofitConfig {
+ private final Retrofit retrofit;
+
+ public RetrofitConfig(String baseUrl) {
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build();
+
+ this.retrofit = new Retrofit.Builder()
+ .baseUrl(baseUrl)
+ .client(client)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+ }
+
+ public AuthResource getAuthResource() throws NullPointerException {
+ return this.retrofit.create(AuthResource.class);
+ }
+
+ public StatementResource getStatementResource() throws NullPointerException {
+ return this.retrofit.create(StatementResource.class);
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/ResponseHelper.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/ResponseHelper.java
new file mode 100644
index 000000000..dc34c0a1d
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/ResponseHelper.java
@@ -0,0 +1,58 @@
+package com.accenture.android.app.testeandroid.data.http.helpers;
+
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.UnknownHostException;
+
+import retrofit2.Response;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class ResponseHelper {
+ public static ErrorResponse createResponse(Response> response) {
+ ErrorResponse errorResponse = new ErrorResponse();
+
+ if (response.errorBody() != null) {
+ String messageErrorBody = "";
+
+ try {
+ messageErrorBody = response.errorBody().string();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (!messageErrorBody.isEmpty()) {
+ errorResponse = new ErrorResponse(0, messageErrorBody);
+ } else {
+ errorResponse.setStatusCode(response.code());
+ errorResponse.setMessage(StatusCode.switchStatusCodeToJson(response.code()));
+ }
+
+ } else {
+ errorResponse.setStatusCode(response.code());
+ errorResponse.setMessage(StatusCode.switchStatusCodeToJson(response.code()));
+ }
+
+ return errorResponse;
+ }
+
+ public static ErrorResponse createResponse(Throwable t) {
+ ErrorResponse errorResponse;
+
+ if (t instanceof UnknownHostException) {
+ errorResponse = new ErrorResponse(2, "Erro: " + t.getMessage() + "\n\nContate o administrador.");
+ } else if (t.getCause() instanceof ConnectException) {
+ errorResponse = new ErrorResponse(1, "Erro: " + t.getMessage() + "\n\nVerifique sua conexão com a internet.");
+ } else if (t.getMessage() == null) {
+ errorResponse = new ErrorResponse(0, "Erro: " + t.toString() + "\n\nContate o administrador.");
+ } else {
+ errorResponse = new ErrorResponse(0, "Erro: " + t.getMessage() + "\n\nContate o administrador.");
+ }
+
+ return errorResponse;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/StatusCode.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/StatusCode.java
new file mode 100644
index 000000000..3b06ff890
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/helpers/StatusCode.java
@@ -0,0 +1,231 @@
+package com.accenture.android.app.testeandroid.data.http.helpers;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatusCode {
+ public static String switchStatusCodeToJson(int statusCode) {
+ String message = "Erro: Entre em contato com os administradores do sistema.";
+
+ if (statusCode >= 100 && statusCode < 200) {
+ String title = "Resposta de informação";
+ String description = "Tente novamente mais tarde.";
+
+ if (statusCode == StatusCodeEnum.Continue.value) {
+ message = title + " (Continue): " + description;
+ } else if (statusCode == StatusCodeEnum.SwitchingProtocols.value) {
+ message = title + " (SwitchingProtocols): " + description;
+ } else if (statusCode == StatusCodeEnum.EarlyHints.value) {
+ message = title + " (EarlyHints): " + description;
+ } else {
+ message = title + ": " + description;
+ }
+ }
+
+ if (statusCode >= 200 && statusCode < 300) {
+ String title = "Sucesso";
+
+ if (statusCode == StatusCodeEnum.OK.value) {
+ message = title + " (OK).";
+ } else if (statusCode == StatusCodeEnum.Created.value) {
+ message = title + " (Created).";
+ } else if (statusCode == StatusCodeEnum.Accepted.value) {
+ message = title + " (Accepted).";
+ } else if (statusCode == StatusCodeEnum.NonAuthoritativeInformation.value) {
+ message = title + " (Non Authoritative Information).";
+ } else if (statusCode == StatusCodeEnum.NoContent.value) {
+ message = title + " (No Content).";
+ } else if (statusCode == StatusCodeEnum.ResetContent.value) {
+ message = title + " (Reset Content).";
+ } else if (statusCode == StatusCodeEnum.PartialContent.value) {
+ message = title + " (Partial Content).";
+ } else {
+ message = title + ".";
+ }
+ }
+
+ if (statusCode >= 300 && statusCode < 400) {
+ String title = "Redirecionamento";
+
+ if (statusCode == StatusCodeEnum.MultipleChoices.value) {
+ message = title + " (Multiple Choices).";
+ } else if (statusCode == StatusCodeEnum.MovedPermanently.value) {
+ message = title + " (Moved Permanently).";
+ } else if (statusCode == StatusCodeEnum.Found.value) {
+ message = title + " (Found).";
+ } else if (statusCode == StatusCodeEnum.SeeOther.value) {
+ message = title + " (See Other).";
+ } else if (statusCode == StatusCodeEnum.NotModified.value) {
+ message = title + " (Not Modified).";
+ } else if (statusCode == StatusCodeEnum.TemporaryRedirect.value) {
+ message = title + " (Temporary Redirect).";
+ } else if (statusCode == StatusCodeEnum.PermanentRedirect.value) {
+ message = title + " (Permanent Redirect).";
+ } else {
+ message = title + ".";
+ }
+ }
+
+ if (statusCode >= 400 && statusCode < 500) {
+ String title = "Erro do cliente";
+ String description = "Entre em contato com os administradores do sistema.";
+
+ if (statusCode == StatusCodeEnum.BadRequest.value) {
+ message = title + " (Bad Request): " + description;
+ } else if (statusCode == StatusCodeEnum.Unauthorized.value) {
+ message = title + " (Unauthorized): " + description;
+ } else if (statusCode == StatusCodeEnum.PaymentRequired.value) {
+ message = title + " (Payment Required): " + description;
+ } else if (statusCode == StatusCodeEnum.Forbidden.value) {
+ message = title + " (Forbidden): " + description;
+ } else if (statusCode == StatusCodeEnum.NotFound.value) {
+ message = title + " (Not Found): " + description;
+ } else if (statusCode == StatusCodeEnum.MethodNotAllowed.value) {
+ message = title + " (Method Not Allowed): " + description;
+ } else if (statusCode == StatusCodeEnum.NotAcceptable.value) {
+ message = title + " (Not Acceptable): " + description;
+ } else if (statusCode == StatusCodeEnum.ProxyAuthenticationRequired.value) {
+ message = title + " (Proxy Authentication Required): " + description;
+ } else if (statusCode == StatusCodeEnum.RequestTimeout.value) {
+ message = title + " (Request Timeout): " + description;
+ } else if (statusCode == StatusCodeEnum.Conflict.value) {
+ message = title + " (Conflict): " + description;
+ } else if (statusCode == StatusCodeEnum.Gone.value) {
+ message = title + " (Gone): " + description;
+ } else if (statusCode == StatusCodeEnum.LengthRequired.value) {
+ message = title + " (Length Required): " + description;
+ } else if (statusCode == StatusCodeEnum.PreconditionFailed.value) {
+ message = title + " (Precondition Failed): " + description;
+ } else if (statusCode == StatusCodeEnum.PayloadTooLarge.value) {
+ message = title + " (Payload Too Large): " + description;
+ } else if (statusCode == StatusCodeEnum.URITooLong.value) {
+ message = title + " (URI Too Long): " + description;
+ } else if (statusCode == StatusCodeEnum.UnsupportedMediaType.value) {
+ message = title + " (Unsupported Media Type): " + description;
+ } else if (statusCode == StatusCodeEnum.RangeNotSatisfiable.value) {
+ message = title + " (Range Not Satisfiable): " + description;
+ } else if (statusCode == StatusCodeEnum.ExpectationFailed.value) {
+ message = title + " (Expectation Failed): " + description;
+ } else if (statusCode == StatusCodeEnum.IAmATeapot.value) {
+ message = title + " (I'm a Teapot): " + description;
+ } else if (statusCode == StatusCodeEnum.UnprocessableEntity.value) {
+ message = title + " (Unprocessable Entity): " + description;
+ } else if (statusCode == StatusCodeEnum.TooEarly.value) {
+ message = title + " (Too Early): " + description;
+ } else if (statusCode == StatusCodeEnum.UpgradeRequired.value) {
+ message = title + " (Upgrade Required): " + description;
+ } else if (statusCode == StatusCodeEnum.PreconditionRequired.value) {
+ message = title + " (Precondition Required): " + description;
+ } else if (statusCode == StatusCodeEnum.TooManyRequests.value) {
+ message = title + " (Too Many Requests): " + description;
+ } else if (statusCode == StatusCodeEnum.RequestHeaderFieldsTooLarge.value) {
+ message = title + " (Request Header Fields Too Large): " + description;
+ } else if (statusCode == StatusCodeEnum.UnavailableForLegalReasons.value) {
+ message = title + " (Unavailable For Legal Reasons): " + description;
+ } else {
+ message = title + ": " + description;
+ }
+ }
+
+ if (statusCode >= 500) {
+ String title = "Erro do servidor";
+ String description = "Tente novamente mais tarde.";
+
+ if (statusCode == StatusCodeEnum.InternalServerError.value) {
+ message = title + " (Internal Server Error): " + description;
+ } else if (statusCode == StatusCodeEnum.NotImplemented.value) {
+ message = title + " (Not Implemented): " + description;
+ } else if (statusCode == StatusCodeEnum.BadGateway.value) {
+ message = title + " (Bad Gateway): " + description;
+ } else if (statusCode == StatusCodeEnum.ServiceUnavailable.value) {
+ message = title + " (Service Unavailable): " + description;
+ } else if (statusCode == StatusCodeEnum.GatewayTimeout.value) {
+ message = title + " (Gateway Timeout): " + description;
+ } else if (statusCode == StatusCodeEnum.HTTPVersionNotSupported.value) {
+ message = title + " (HTTP Version Not Supported): " + description;
+ } else if (statusCode == StatusCodeEnum.VariantAlsoNegotiates.value) {
+ message = title + " (Variant Also Negotiates): " + description;
+ } else if (statusCode == StatusCodeEnum.InsufficientStorage.value) {
+ message = title + " (Insufficient Storage): " + description;
+ } else if (statusCode == StatusCodeEnum.LoopDetected.value) {
+ message = title + " (Loop Detected): " + description;
+ } else if (statusCode == StatusCodeEnum.NotExtended.value) {
+ message = title + " (Not Extended): " + description;
+ } else if (statusCode == StatusCodeEnum.NetworkAuthenticationRequired.value) {
+ message = title + " (Network Authentication Required): " + description;
+ } else {
+ message = title + ": " + description;
+ }
+ }
+
+ return message;
+ }
+
+ public enum StatusCodeEnum {
+ Continue(100),
+ SwitchingProtocols(101),
+ EarlyHints(103),
+
+ OK(200),
+ Created(201),
+ Accepted(202),
+ NonAuthoritativeInformation(203),
+ NoContent(204),
+ ResetContent(205),
+ PartialContent(206),
+
+ MultipleChoices(300),
+ MovedPermanently(301),
+ Found(302),
+ SeeOther(303),
+ NotModified(304),
+ TemporaryRedirect(307),
+ PermanentRedirect(308),
+
+ BadRequest(400),
+ Unauthorized(401),
+ PaymentRequired(402),
+ Forbidden(403),
+ NotFound(404),
+ MethodNotAllowed(405),
+ NotAcceptable(406),
+ ProxyAuthenticationRequired(407),
+ RequestTimeout(408),
+ Conflict(409),
+ Gone(410),
+ LengthRequired(411),
+ PreconditionFailed(412),
+ PayloadTooLarge(413),
+ URITooLong(414),
+ UnsupportedMediaType(415),
+ RangeNotSatisfiable(416),
+ ExpectationFailed(417),
+ IAmATeapot(418),
+ UnprocessableEntity(422),
+ TooEarly(425),
+ UpgradeRequired(426),
+ PreconditionRequired(428),
+ TooManyRequests(429),
+ RequestHeaderFieldsTooLarge(431),
+ UnavailableForLegalReasons(451),
+
+ InternalServerError(500),
+ NotImplemented(501),
+ BadGateway(502),
+ ServiceUnavailable(503),
+ GatewayTimeout(504),
+ HTTPVersionNotSupported(505),
+ VariantAlsoNegotiates(506),
+ InsufficientStorage(507),
+ LoopDetected(508),
+ NotExtended(510),
+ NetworkAuthenticationRequired(511);
+
+ public int value;
+
+ StatusCodeEnum(int value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/StatementProvider.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/StatementProvider.java
new file mode 100644
index 000000000..e12cb668f
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/StatementProvider.java
@@ -0,0 +1,78 @@
+package com.accenture.android.app.testeandroid.data.http.providers;
+
+import android.util.Log;
+
+import com.accenture.android.app.testeandroid.data.converters.StatementConverter;
+import com.accenture.android.app.testeandroid.data.http.helpers.StatusCode;
+import com.accenture.android.app.testeandroid.data.http.providers.generics.BaseProvider;
+import com.accenture.android.app.testeandroid.data.http.resources.StatementResource;
+import com.accenture.android.app.testeandroid.data.http.responses.StatementResponse;
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.accenture.android.app.testeandroid.domain.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatementProvider extends BaseProvider {
+ private StatementResource resource;
+
+ private Call callBuscarStatements;
+
+ public StatementProvider(String baseUrl) {
+ super(baseUrl);
+
+ this.resource = this.retrofit.getStatementResource();
+ }
+
+ @Override
+ public void finish() {
+ if (this.callBuscarStatements != null) {
+ this.callBuscarStatements.cancel();
+ }
+ }
+
+ public void buscarStatements(final ExpectedResponseStatements callback, Long userId) {
+ this.callBuscarStatements = this.resource.getStatements(userId);
+ this.callBuscarStatements.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.code() == StatusCode.StatusCodeEnum.OK.value) {
+ ErrorResponse error = response.body().getError();
+
+ if (error.getStatusCode() == null) {
+ ArrayList statements = StatementConverter.toDomain(new ArrayList<>(response.body().getData()));
+
+ callback.onSuccess("Busca efetuada com sucesso.", statements);
+ } else {
+ callback.onFailure(error);
+ }
+ } else {
+ callback.onFailure(new ErrorResponse(response.code(), response.message()));
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ if (call.isCanceled()) {
+ Log.e(TAG, "buscarStatements: Requisição cancelada.");
+ } else {
+ callback.onFailure(new ErrorResponse(0, t.getMessage()));
+ }
+ }
+ });
+ }
+
+ public interface ExpectedResponseStatements {
+ void onSuccess(String message, List statements);
+
+ void onFailure(ErrorResponse error);
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/UserAccountProvider.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/UserAccountProvider.java
new file mode 100644
index 000000000..cdebeea17
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/UserAccountProvider.java
@@ -0,0 +1,75 @@
+package com.accenture.android.app.testeandroid.data.http.providers;
+
+import android.util.Log;
+
+import com.accenture.android.app.testeandroid.data.converters.UserAccountConverter;
+import com.accenture.android.app.testeandroid.data.http.helpers.StatusCode;
+import com.accenture.android.app.testeandroid.data.http.providers.generics.BaseProvider;
+import com.accenture.android.app.testeandroid.data.http.resources.AuthResource;
+import com.accenture.android.app.testeandroid.data.http.responses.UserAccountResponse;
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class UserAccountProvider extends BaseProvider {
+ private AuthResource resource;
+
+ private Call callLogin;
+
+ public UserAccountProvider(String baseUrl) {
+ super(baseUrl);
+
+ this.resource = this.retrofit.getAuthResource();
+ }
+
+ public void efetuarLogin(final ExpectedResponseLogin callback, String user, String password) {
+ this.callLogin = this.resource.login(user, password);
+ this.callLogin.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.code() == StatusCode.StatusCodeEnum.OK.value) {
+ ErrorResponse error = response.body().getError();
+
+ if (error.getStatusCode() == null) {
+ UserAccount statements = UserAccountConverter.toDomain(response.body().getData());
+
+ callback.onSuccess("Busca efetuada com sucesso.", statements);
+ } else {
+ callback.onFailure(error);
+ }
+ } else {
+ callback.onFailure(new ErrorResponse(response.code(), response.message()));
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ if (call.isCanceled()) {
+ Log.e(TAG, "efetuarLogin: Requisição cancelada.");
+ } else {
+ callback.onFailure(new ErrorResponse(0, t.getMessage()));
+ }
+ }
+ });
+ }
+
+ @Override
+ public void finish() {
+ if (this.callLogin != null) {
+ this.callLogin.cancel();
+ }
+ }
+
+ public interface ExpectedResponseLogin {
+ void onSuccess(String message, UserAccount userAccount);
+
+ void onFailure(ErrorResponse error);
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/generics/BaseProvider.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/generics/BaseProvider.java
new file mode 100644
index 000000000..7d515d136
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/providers/generics/BaseProvider.java
@@ -0,0 +1,19 @@
+package com.accenture.android.app.testeandroid.data.http.providers.generics;
+
+import com.accenture.android.app.testeandroid.data.http.RetrofitConfig;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public abstract class BaseProvider {
+ protected final String TAG = "CustomLog - " + this.getClass().getSimpleName();
+
+ protected final RetrofitConfig retrofit;
+
+ public BaseProvider(String baseUrl) {
+ this.retrofit = new RetrofitConfig(baseUrl);
+ }
+
+ public abstract void finish();
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/AuthResource.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/AuthResource.java
new file mode 100644
index 000000000..f1123a5dc
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/AuthResource.java
@@ -0,0 +1,18 @@
+package com.accenture.android.app.testeandroid.data.http.resources;
+
+import com.accenture.android.app.testeandroid.data.http.responses.UserAccountResponse;
+
+import retrofit2.Call;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public interface AuthResource {
+ @FormUrlEncoded
+ @POST("login")
+ Call login(@Field("user") String user, @Field("password") String password);
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/StatementResource.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/StatementResource.java
new file mode 100644
index 000000000..6cf3b3340
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/resources/StatementResource.java
@@ -0,0 +1,16 @@
+package com.accenture.android.app.testeandroid.data.http.resources;
+
+import com.accenture.android.app.testeandroid.data.http.responses.StatementResponse;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Path;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public interface StatementResource {
+ @GET("statements/{userId}")
+ Call getStatements(@Path("userId") Long userId);
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/StatementResponse.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/StatementResponse.java
new file mode 100644
index 000000000..6da8b468e
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/StatementResponse.java
@@ -0,0 +1,57 @@
+package com.accenture.android.app.testeandroid.data.http.responses;
+
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatementResponse {
+ @SerializedName("statementList")
+ private List data;
+ private ErrorResponse error;
+
+ public static class StatementData {
+ private String title;
+ private String desc;
+ private String date;
+ private Double value;
+
+ public StatementData() {
+ }
+
+ public StatementData(String title, String desc, String date, Double value) {
+ this.title = title;
+ this.desc = desc;
+ this.date = date;
+ this.value = value;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public Double getValue() {
+ return value;
+ }
+ }
+
+ public List getData() {
+ return data;
+ }
+
+ public ErrorResponse getError() {
+ return error;
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/UserAccountResponse.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/UserAccountResponse.java
new file mode 100644
index 000000000..6e14f5826
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/UserAccountResponse.java
@@ -0,0 +1,61 @@
+package com.accenture.android.app.testeandroid.data.http.responses;
+
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class UserAccountResponse {
+ @SerializedName("userAccount")
+ private UserAccountResponse.UserAccountData data;
+ private ErrorResponse error;
+
+ public static class UserAccountData {
+ private Long userId;
+ private String name;
+ private String bankAccount;
+ private String agency;
+ private Double balance;
+
+ public UserAccountData() {
+ }
+
+ public UserAccountData(Long userId, String name, String bankAccount, String agency, Double balance) {
+ this.userId = userId;
+ this.name = name;
+ this.bankAccount = bankAccount;
+ this.agency = agency;
+ this.balance = balance;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getBankAccount() {
+ return bankAccount;
+ }
+
+ public String getAgency() {
+ return agency;
+ }
+
+ public Double getBalance() {
+ return balance;
+ }
+ }
+
+ public UserAccountData getData() {
+ return data;
+ }
+
+ public ErrorResponse getError() {
+ return error;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/generics/ErrorResponse.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/generics/ErrorResponse.java
new file mode 100644
index 000000000..02e0aa3d1
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/data/http/responses/generics/ErrorResponse.java
@@ -0,0 +1,49 @@
+package com.accenture.android.app.testeandroid.data.http.responses.generics;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class ErrorResponse {
+ private Integer code;
+ private String message;
+
+ public ErrorResponse() {
+ }
+
+ public ErrorResponse(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public Integer getStatusCode() {
+ return code;
+ }
+
+ public void setStatusCode(Integer code) {
+ this.code = code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessageFormat() {
+ String error = "";
+ try {
+ JSONObject json = new JSONObject(this.message);
+ error = json.getString("error");
+ } catch (JSONException ex) {
+ ex.printStackTrace();
+ }
+
+ return error;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/Statement.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/Statement.java
new file mode 100644
index 000000000..bfed0e058
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/Statement.java
@@ -0,0 +1,119 @@
+package com.accenture.android.app.testeandroid.domain;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class Statement implements Parcelable {
+ private String title;
+ private String desc;
+ private String date;
+ private Double value;
+
+ public Statement() {
+ }
+
+ protected Statement(Parcel in) {
+ title = in.readString();
+ desc = in.readString();
+ date = in.readString();
+ if (in.readByte() == 0) {
+ value = null;
+ } else {
+ value = in.readDouble();
+ }
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Statement createFromParcel(Parcel in) {
+ return new Statement(in);
+ }
+
+ @Override
+ public Statement[] newArray(int size) {
+ return new Statement[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(title);
+ dest.writeString(desc);
+ dest.writeString(date);
+ if (value == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeDouble(value);
+ }
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ public Double getValue() {
+ return value;
+ }
+
+ public void setValue(Double value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return "Statement{" +
+ "title='" + title + '\'' +
+ ", desc='" + desc + '\'' +
+ ", date='" + date + '\'' +
+ ", value=" + value +
+ '}';
+ }
+ public Calendar getDateCalendar() throws ParseException {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
+
+ Date date = format.parse(this.date);
+
+ Calendar calendar = Calendar.getInstance();
+
+ calendar.setTime(date);
+
+ return calendar;
+ }
+
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/UserAccount.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/UserAccount.java
new file mode 100644
index 000000000..9e8826ae9
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/domain/UserAccount.java
@@ -0,0 +1,122 @@
+package com.accenture.android.app.testeandroid.domain;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class UserAccount implements Parcelable {
+ private Long userId;
+ private String name;
+ private String bankAccount;
+ private String agency;
+ private Double balance;
+
+ public UserAccount() {
+ }
+
+ protected UserAccount(Parcel in) {
+ if (in.readByte() == 0) {
+ userId = null;
+ } else {
+ userId = in.readLong();
+ }
+ name = in.readString();
+ bankAccount = in.readString();
+ agency = in.readString();
+ if (in.readByte() == 0) {
+ balance = null;
+ } else {
+ balance = in.readDouble();
+ }
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public UserAccount createFromParcel(Parcel in) {
+ return new UserAccount(in);
+ }
+
+ @Override
+ public UserAccount[] newArray(int size) {
+ return new UserAccount[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (userId == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeLong(userId);
+ }
+ dest.writeString(name);
+ dest.writeString(bankAccount);
+ dest.writeString(agency);
+ if (balance == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeDouble(balance);
+ }
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getBankAccount() {
+ return bankAccount;
+ }
+
+ public void setBankAccount(String bankAccount) {
+ this.bankAccount = bankAccount;
+ }
+
+ public String getAgency() {
+ return agency;
+ }
+
+ public void setAgency(String agency) {
+ this.agency = agency;
+ }
+
+ public Double getBalance() {
+ return balance;
+ }
+
+ public void setBalance(Double balance) {
+ this.balance = balance;
+ }
+
+ @Override
+ public String toString() {
+ return "UserAccount{" +
+ "userId=" + userId +
+ ", name='" + name + '\'' +
+ ", bankAccount='" + bankAccount + '\'' +
+ ", agency='" + agency + '\'' +
+ ", balance=" + balance +
+ '}';
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FieldHelper.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FieldHelper.java
new file mode 100644
index 000000000..fff237c94
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FieldHelper.java
@@ -0,0 +1,76 @@
+package com.accenture.android.app.testeandroid.helpers;
+
+import java.util.InputMismatchException;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class FieldHelper {
+ public static boolean isCPF(String CPF) {
+ // Retira qualquer caracter que foi digitado pelo usuário é válido em um CPF
+ CPF = CPF.replaceAll("[.]", "").replaceAll("[-]", "")
+ .replaceAll("[ ]", "");
+
+ // considera-se erro CPF's formados por uma sequencia de numeros iguais
+ if (CPF.equals("00000000000") ||
+ CPF.equals("11111111111") ||
+ CPF.equals("22222222222") || CPF.equals("33333333333") ||
+ CPF.equals("44444444444") || CPF.equals("55555555555") ||
+ CPF.equals("66666666666") || CPF.equals("77777777777") ||
+ CPF.equals("88888888888") || CPF.equals("99999999999") ||
+ (CPF.length() != 11))
+ return (false);
+
+ char dig10, dig11;
+ int sm, i, r, num, peso;
+
+ try {
+ // Calculo do 1º. Digito Verificador
+ sm = 0;
+ peso = 10;
+ for (i = 0; i < 9; i++) {
+ // converte o i-esimo caractere do CPF em um numero:
+ // por exemplo, transforma o caractere '0' no inteiro 0
+ // (48 eh a posicao de '0' na tabela ASCII)
+ num = (int) (CPF.charAt(i) - 48);
+ sm = sm + (num * peso);
+ peso = peso - 1;
+ }
+
+ r = 11 - (sm % 11);
+ if ((r == 10) || (r == 11))
+ dig10 = '0';
+ else dig10 = (char) (r + 48); // converte no respectivo caractere numerico
+
+ // Calculo do 2º. Digito Verificador
+ sm = 0;
+ peso = 11;
+ for (i = 0; i < 10; i++) {
+ num = (int) (CPF.charAt(i) - 48);
+ sm = sm + (num * peso);
+ peso = peso - 1;
+ }
+
+ r = 11 - (sm % 11);
+ if ((r == 10) || (r == 11))
+ dig11 = '0';
+ else dig11 = (char) (r + 48);
+
+ // Verifica se os digitos calculados conferem com os digitos informados.
+ if ((dig10 == CPF.charAt(9)) && (dig11 == CPF.charAt(10)))
+ return (true);
+ else return (false);
+ } catch (InputMismatchException erro) {
+ return (false);
+ }
+ }
+
+ public static boolean isEmail(String email) {
+ return email.matches("([a-z0-9-._]+)@([a-z]+).([a-z]+).([a-z]+)");
+ }
+
+ public static boolean isPassword(String password) {
+ return password.matches("^(?=.*?[A-Z])(?=(.*[\\d]){1,})(?=(.*[\\W]){1,})(?!.*\\s).{3,}$");
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FormatHelper.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FormatHelper.java
new file mode 100644
index 000000000..8ffd1a0ed
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/helpers/FormatHelper.java
@@ -0,0 +1,48 @@
+package com.accenture.android.app.testeandroid.helpers;
+
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class FormatHelper {
+ public static String formatarReal(Double valor) {
+ String formated = NumberFormat.getCurrencyInstance(new Locale("pt", "BR")).format(valor);
+
+ // Verifica se número formatado está entre parenteses
+ // Se sim, número é negativo, então formata o número para retirar os parenteses e
+ // colocar o '-' na frente.
+ if (formated.contains("(")) {
+ formated = formated.replaceAll("[()]", "");
+
+ formated = "- " + formated;
+ }
+
+ return formated;
+ }
+
+ public static String formatarAgenciaBanco(String agencia) {
+ if (agencia.length() < 9) {
+ int numerosFaltantes = 9 - agencia.length();
+
+ StringBuilder agenciaBuilder = new StringBuilder(agencia);
+ for (int i = 0; i < numerosFaltantes; i++) {
+ agenciaBuilder.insert(0, "0");
+ }
+ agencia = agenciaBuilder.toString();
+ }
+ return agencia.substring(0, 2) + "." + agencia.substring(2, agencia.length() - 1) + "-" + agencia.substring(agencia.length() - 1);
+ }
+
+ public static String formatarData(Calendar data) {
+ Integer dia = data.get(Calendar.DAY_OF_MONTH);
+ String mes = new SimpleDateFormat("MM", Locale.getDefault()).format(data.getTime());
+ Integer ano = data.get(Calendar.YEAR);
+
+ return String.format(Locale.getDefault(), "%d/%s/%d", dia, mes, ano);
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BasePresenter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BasePresenter.java
new file mode 100644
index 000000000..06899cc82
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BasePresenter.java
@@ -0,0 +1,10 @@
+package com.accenture.android.app.testeandroid.presentation;
+
+import androidx.lifecycle.LifecycleObserver;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public interface BasePresenter extends LifecycleObserver {
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BaseView.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BaseView.java
new file mode 100644
index 000000000..13719bc8a
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/BaseView.java
@@ -0,0 +1,8 @@
+package com.accenture.android.app.testeandroid.presentation;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public interface BaseView {
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginActivity.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginActivity.java
new file mode 100644
index 000000000..7a61bc289
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginActivity.java
@@ -0,0 +1,147 @@
+package com.accenture.android.app.testeandroid.presentation.login;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.accenture.android.app.testeandroid.databinding.ActivityLoginBinding;
+import com.accenture.android.app.testeandroid.helpers.FieldHelper;
+import com.accenture.android.app.testeandroid.presentation.main.MainActivity;
+import com.google.android.material.snackbar.Snackbar;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class LoginActivity extends AppCompatActivity implements LoginContract.View {
+ private final static String TAG = "CustomLog - " + LoginActivity.class.getSimpleName();
+
+ private ActivityLoginBinding binding;
+
+ private LoginContract.Presenter presenter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.binding = ActivityLoginBinding.inflate(getLayoutInflater());
+
+ this.presenter = new LoginPresenter(this, this.getLifecycle(), this);
+
+ setContentView(this.binding.getRoot());
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ this.initEvents();
+ }
+
+ private void initEvents() {
+ this.binding.btnLogar.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (validateFields()) {
+ String user = binding.edtUser.getText().toString();
+ String password = binding.edtPassword.getText().toString();
+
+ presenter.efetuarLogin(user, password);
+ } else {
+ setFeedback("Revise os campos!");
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setLoading() {
+ this.binding.pgbLoading.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void unsetLoading() {
+ this.binding.pgbLoading.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void setContent() {
+ this.binding.btnLogar.setEnabled(true);
+ }
+
+ @Override
+ public void unsetContent() {
+ this.binding.btnLogar.setEnabled(false);
+ }
+
+ @Override
+ public void setFeedback(String message) {
+ Snackbar.make(this.binding.getRoot(), message, Snackbar.LENGTH_LONG)
+ .show();
+ }
+
+ @Override
+ public void setError(String message) {
+ this.binding.txtFeedbackError.setVisibility(View.VISIBLE);
+ this.binding.txtFeedbackError.setText(message);
+ }
+
+ @Override
+ public void unsetError() {
+ this.binding.txtFeedbackError.setVisibility(View.GONE);
+ this.binding.txtFeedbackError.setText("");
+ }
+
+ @Override
+ public void setLoginRecente(String name) {
+ this.binding.lltRecentLoginContainer.setVisibility(View.VISIBLE);
+ this.binding.txtLoginRecente.setText(name);
+ }
+
+ @Override
+ public void navigateToMainActivity() {
+ Intent intent = new Intent(LoginActivity.this, MainActivity.class);
+
+ startActivity(intent);
+
+ this.finish();
+ }
+
+ private boolean validateFields() {
+ boolean filled = true;
+
+ // Valida campo "User"
+ this.binding.tilUser.setErrorEnabled(false);
+ if (this.binding.edtUser.getText().toString().isEmpty()) {
+ this.binding.tilUser.setError("Campo obrigatório!");
+ filled = false;
+ } else if (this.binding.edtUser.getText().toString().contains("@")) {
+ if (!FieldHelper.isEmail(this.binding.edtUser.getText().toString())) {
+ this.binding.tilUser.setError("CPF ou e-mail inválido!");
+ filled = false;
+ }
+ } else if (!FieldHelper.isCPF(this.binding.edtUser.getText().toString())) {
+ this.binding.tilUser.setError("CPF ou e-mail inválido!");
+ filled = false;
+ }
+
+ this.unsetError();
+ // Valida campo "Password"
+ this.binding.tilPassword.setErrorEnabled(false);
+ if (this.binding.edtPassword.getText().toString().isEmpty()) {
+ this.binding.tilPassword.setError("Campo obrigatório!");
+ filled = false;
+ } else if (this.binding.edtPassword.getText().length() < 3) {
+ this.binding.tilPassword.setError("Campo inválido!");
+ filled = false;
+ } else if (!FieldHelper.isPassword(this.binding.edtPassword.getText().toString())) {
+ this.binding.tilPassword.setError("Campo inválido!");
+ this.setError("A senha deve conter pelo menos uma letra maiúscula, um caracter especial e um caracter alfanumérico.");
+
+ filled = false;
+ }
+
+ return filled;
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginContract.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginContract.java
new file mode 100644
index 000000000..65bfa05ad
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginContract.java
@@ -0,0 +1,34 @@
+package com.accenture.android.app.testeandroid.presentation.login;
+
+import com.accenture.android.app.testeandroid.presentation.BasePresenter;
+import com.accenture.android.app.testeandroid.presentation.BaseView;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+interface LoginContract {
+ interface Presenter extends BasePresenter {
+ void efetuarLogin(String user, String password);
+ }
+
+ interface View extends BaseView {
+ void setLoading();
+
+ void unsetLoading();
+
+ void setContent();
+
+ void unsetContent();
+
+ void setFeedback(String message);
+
+ void setError(String message);
+
+ void unsetError();
+
+ void setLoginRecente(String name);
+
+ void navigateToMainActivity();
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginPresenter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginPresenter.java
new file mode 100644
index 000000000..481a23118
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/login/LoginPresenter.java
@@ -0,0 +1,104 @@
+package com.accenture.android.app.testeandroid.presentation.login;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.OnLifecycleEvent;
+
+import com.accenture.android.app.testeandroid.data.http.providers.UserAccountProvider;
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+import com.accenture.android.app.testeandroid.utils.AuthManager;
+
+import java.util.Locale;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+class LoginPresenter implements LoginContract.Presenter {
+ private final static String TAG = "CustomLog - " + LoginPresenter.class.getSimpleName();
+
+ private LoginContract.View view;
+ private Context context;
+
+ private AuthManager authManager;
+
+ private UserAccountProvider userAccountProvider;
+ private UserAccountProvider.ExpectedResponseLogin userAccountCallback;
+
+ LoginPresenter(Context context, Lifecycle lifecycle, LoginContract.View view) {
+ this.context = context;
+ this.view = view;
+ lifecycle.addObserver(this);
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ private void onStart() {
+ this.initEvents();
+
+ this.initAuthManager();
+ this.initProviders();
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ private void onResume() {
+ this.buscarUsuarioLogadoRecentemente();
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+ private void onPause() {
+ this.userAccountProvider.finish();
+ }
+
+ private void initEvents() {
+ this.userAccountCallback = new UserAccountProvider.ExpectedResponseLogin() {
+ @Override
+ public void onSuccess(String message, UserAccount userAccount) {
+ view.unsetLoading();
+ view.setContent();
+
+ authManager.setUserAccount(userAccount);
+
+ view.navigateToMainActivity();
+ }
+
+ @Override
+ public void onFailure(ErrorResponse error) {
+ view.unsetLoading();
+ view.setContent();
+
+ authManager.clearUserAccount();
+
+ view.setFeedback(String.format(Locale.getDefault(), "%d: %s", error.getStatusCode(), error.getMessage()));
+ }
+ };
+ }
+
+ private void initAuthManager() {
+ this.authManager = new AuthManager(this.context);
+ }
+
+ private void initProviders() {
+ String url = "https://bank-app-test.herokuapp.com/api/";
+
+ this.userAccountProvider = new UserAccountProvider(url);
+ }
+
+ @Override
+ public void efetuarLogin(String user, String password) {
+ this.view.unsetContent();
+ this.view.setLoading();
+
+ this.userAccountProvider.efetuarLogin(this.userAccountCallback, user, password);
+ }
+
+ private void buscarUsuarioLogadoRecentemente() {
+ UserAccount userAccount = this.authManager.getUserAccount();
+
+ if (userAccount.getUserId() != null) {
+ this.view.setLoginRecente(userAccount.getName());
+ }
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainActivity.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainActivity.java
new file mode 100644
index 000000000..c657b9e38
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainActivity.java
@@ -0,0 +1,145 @@
+package com.accenture.android.app.testeandroid.presentation.main;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+import com.accenture.android.app.testeandroid.R;
+import com.accenture.android.app.testeandroid.databinding.ActivityMainBinding;
+import com.accenture.android.app.testeandroid.domain.Statement;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+import com.accenture.android.app.testeandroid.helpers.FormatHelper;
+import com.accenture.android.app.testeandroid.presentation.login.LoginActivity;
+import com.accenture.android.app.testeandroid.presentation.main.adapters.StatementsRecyclerAdapter;
+import com.google.android.material.snackbar.Snackbar;
+
+import java.util.ArrayList;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class MainActivity extends AppCompatActivity implements MainContract.View {
+ private final static String TAG = "CustomLog - " + MainActivity.class.getSimpleName();
+
+ private ActivityMainBinding binding;
+
+ private MainContract.Presenter presenter;
+
+ private StatementsRecyclerAdapter statementsRecyclerAdapter;
+ private ArrayList statements = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.binding = ActivityMainBinding.inflate(getLayoutInflater());
+
+ this.presenter = new MainPresenter(this, this.getLifecycle(), this);
+
+ setContentView(this.binding.getRoot());
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ this.initEvents();
+ this.configRecyclerView();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ this.presenter.buscarStatements(1L);
+ }
+
+ private void initEvents() {
+ this.binding.iclAppBar.btnLogout.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ presenter.efetuarLogout();
+ }
+ });
+ }
+
+ private void configRecyclerView() {
+ LinearLayoutManager lltManager = new LinearLayoutManager(this);
+ this.binding.rcvStatements.setLayoutManager(lltManager);
+
+ DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, lltManager.getOrientation());
+ dividerItemDecoration.setDrawable(this.getResources().getDrawable(R.drawable.shape_divider_transparent));
+ this.binding.rcvStatements.addItemDecoration(dividerItemDecoration);
+
+ this.statementsRecyclerAdapter = new StatementsRecyclerAdapter(this, this.statements);
+ this.binding.rcvStatements.setAdapter(this.statementsRecyclerAdapter);
+ }
+
+ @Override
+ public void setLoading() {
+ this.binding.pgbLoading.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void unsetLoading() {
+ this.binding.pgbLoading.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void setContent() {
+ this.binding.txtTitulo.setVisibility(View.VISIBLE);
+ this.binding.rcvStatements.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void unsetContent() {
+ this.binding.txtTitulo.setVisibility(View.INVISIBLE);
+ this.binding.rcvStatements.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void setFeedback(String message) {
+ Snackbar.make(this.binding.getRoot(), message, Snackbar.LENGTH_LONG)
+ .show();
+ }
+
+ @Override
+ public void setUserAccount(UserAccount userAccount) {
+ this.binding.iclAppBar.txtUserName.setText(userAccount.getName());
+ this.binding.iclAppBar.txtConta.setText(getResources().getString(R.string.app_main_txt_text_conta, userAccount.getBankAccount(), FormatHelper.formatarAgenciaBanco(userAccount.getAgency())));
+ }
+
+ @Override
+ public void setStatements(ArrayList statements) {
+ this.statements.clear();
+
+ this.statements.addAll(statements);
+
+ this.statementsRecyclerAdapter.notifyDataSetChanged();
+
+ this.binding.iclAppBar.txtSaldo.setText(FormatHelper.formatarReal(this.contarSaldo(statements)));
+ }
+
+ @Override
+ public void navigateToLoginActivity() {
+ Intent intent = new Intent(MainActivity.this, LoginActivity.class);
+
+ startActivity(intent);
+
+ this.finish();
+ }
+
+ private Double contarSaldo(ArrayList statements) {
+ Double saldo = 0.0;
+
+ for (Statement statement : statements) {
+ saldo = saldo + statement.getValue();
+ }
+
+ return saldo;
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainContract.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainContract.java
new file mode 100644
index 000000000..df93ef52c
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainContract.java
@@ -0,0 +1,38 @@
+package com.accenture.android.app.testeandroid.presentation.main;
+
+import com.accenture.android.app.testeandroid.domain.Statement;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+import com.accenture.android.app.testeandroid.presentation.BasePresenter;
+import com.accenture.android.app.testeandroid.presentation.BaseView;
+
+import java.util.ArrayList;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+interface MainContract {
+ interface Presenter extends BasePresenter {
+ void buscarStatements(Long userId);
+
+ void efetuarLogout();
+ }
+
+ interface View extends BaseView {
+ void setLoading();
+
+ void unsetLoading();
+
+ void setContent();
+
+ void unsetContent();
+
+ void setFeedback(String message);
+
+ void setUserAccount(UserAccount userAccount);
+
+ void setStatements(ArrayList statements);
+
+ void navigateToLoginActivity();
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainPresenter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainPresenter.java
new file mode 100644
index 000000000..351fe3dd8
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/MainPresenter.java
@@ -0,0 +1,100 @@
+package com.accenture.android.app.testeandroid.presentation.main;
+
+import android.content.Context;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.OnLifecycleEvent;
+
+import com.accenture.android.app.testeandroid.data.http.providers.StatementProvider;
+import com.accenture.android.app.testeandroid.data.http.responses.generics.ErrorResponse;
+import com.accenture.android.app.testeandroid.domain.Statement;
+import com.accenture.android.app.testeandroid.utils.AuthManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+class MainPresenter implements MainContract.Presenter {
+ private final static String TAG = "CustomLog - " + MainPresenter.class.getSimpleName();
+
+ private MainContract.View view;
+ private Context context;
+
+ private AuthManager authManager;
+
+ private StatementProvider statementProvider;
+ private StatementProvider.ExpectedResponseStatements statementsCallback;
+
+ MainPresenter(Context context, Lifecycle lifecycle, MainContract.View view) {
+ this.context = context;
+ this.view = view;
+ lifecycle.addObserver(this);
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_START)
+ private void onStart() {
+ this.initEvents();
+
+ this.initAuthManager();
+ this.initProviders();
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ private void onResume() {
+ this.view.setUserAccount(this.authManager.getUserAccount());
+ }
+
+ @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+ private void onPause() {
+ this.statementProvider.finish();
+ }
+
+ private void initEvents() {
+ this.statementsCallback = new StatementProvider.ExpectedResponseStatements() {
+ @Override
+ public void onSuccess(String message, List statements) {
+ view.unsetLoading();
+ view.setContent();
+
+ view.setStatements(new ArrayList<>(statements));
+ }
+
+ @Override
+ public void onFailure(ErrorResponse error) {
+ view.unsetLoading();
+ view.setContent();
+
+ view.setFeedback(String.format(Locale.getDefault(), "%d: %s", error.getStatusCode(), error.getMessage()));
+ }
+ };
+ }
+
+ private void initAuthManager() {
+ this.authManager = new AuthManager(this.context);
+ }
+
+ private void initProviders() {
+ String url = "https://bank-app-test.herokuapp.com/api/";
+
+ this.statementProvider = new StatementProvider(url);
+ }
+
+ @Override
+ public void buscarStatements(Long userId) {
+ this.view.setLoading();
+ this.view.unsetContent();
+
+ this.statementProvider.buscarStatements(this.statementsCallback, userId);
+ }
+
+ @Override
+ public void efetuarLogout() {
+ this.authManager.clearUserAccount();
+
+ this.view.navigateToLoginActivity();
+ }
+}
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/adapters/StatementsRecyclerAdapter.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/adapters/StatementsRecyclerAdapter.java
new file mode 100644
index 000000000..82fc06b2a
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/presentation/main/adapters/StatementsRecyclerAdapter.java
@@ -0,0 +1,83 @@
+package com.accenture.android.app.testeandroid.presentation.main.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.accenture.android.app.testeandroid.databinding.ItemRecyclerStatementBinding;
+import com.accenture.android.app.testeandroid.domain.Statement;
+import com.accenture.android.app.testeandroid.helpers.FormatHelper;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatementsRecyclerAdapter extends RecyclerView.Adapter {
+ private final static String TAG = "CustomLog - " + StatementsRecyclerAdapter.class.getSimpleName();
+
+ private final Context context;
+
+ private ArrayList statements;
+
+ public StatementsRecyclerAdapter(Context context, ArrayList statements) {
+ this.context = context;
+ this.statements = statements;
+ }
+
+ @NonNull
+ @Override
+ public StatementsRecyclerAdapter.StatementViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ ItemRecyclerStatementBinding binding = ItemRecyclerStatementBinding.inflate(layoutInflater, parent, false);
+
+ return new StatementViewHolder(this.context, binding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull StatementsRecyclerAdapter.StatementViewHolder holder, int position) {
+ holder.bindStatement(this.statements.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return this.statements.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ public static class StatementViewHolder extends RecyclerView.ViewHolder {
+ private final static String TAG = "CustomLog - " + StatementViewHolder.class.getSimpleName();
+
+ private Context context;
+ private ItemRecyclerStatementBinding binding;
+
+ public StatementViewHolder(Context context, ItemRecyclerStatementBinding binding) {
+ super(binding.getRoot());
+
+ this.context = context;
+ this.binding = binding;
+ }
+
+ public void bindStatement(Statement statement) {
+ this.binding.txtTitulo.setText(statement.getTitle());
+ this.binding.txtDescricao.setText(statement.getDesc());
+
+ try {
+ this.binding.txtData.setText(FormatHelper.formatarData(statement.getDateCalendar()));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ this.binding.txtValor.setText(FormatHelper.formatarReal(statement.getValue()));
+ }
+ }
+}
diff --git a/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/utils/AuthManager.java b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/utils/AuthManager.java
new file mode 100644
index 000000000..84fa92270
--- /dev/null
+++ b/TesteAndroid/app/src/main/java/com/accenture/android/app/testeandroid/utils/AuthManager.java
@@ -0,0 +1,54 @@
+package com.accenture.android.app.testeandroid.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Created by Denis Magno on 09/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class AuthManager {
+ private static final String USER_AUTH_KEY = "USER_AUTH_KEY_JWT";
+ private static final String USER_AUTH_OBJECT = "USER_AUTH_OBJECT";
+ private final SharedPreferences sharedPreferences;
+ private final SharedPreferences.Editor editor;
+
+ public AuthManager(Context context) {
+ this.sharedPreferences = context.getSharedPreferences(USER_AUTH_KEY, 0);
+ this.editor = this.sharedPreferences.edit();
+ }
+
+ public void setUserAccount(UserAccount userAccount) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(userAccount);
+ this.editor.putString(USER_AUTH_OBJECT, json);
+ this.editor.apply();
+ } catch (JsonProcessingException var5) {
+ var5.printStackTrace();
+ }
+ }
+
+ public UserAccount getUserAccount() {
+ UserAccount userAccount = new UserAccount();
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ String json = this.sharedPreferences.getString(USER_AUTH_OBJECT, new UserAccount().toString());
+ userAccount = (UserAccount) mapper.readValue(json, UserAccount.class);
+ } catch (JsonProcessingException var4) {
+ var4.printStackTrace();
+ }
+
+ return userAccount;
+ }
+
+ public void clearUserAccount() {
+ this.editor.remove(USER_AUTH_OBJECT);
+ this.editor.commit();
+ }
+}
diff --git a/TesteAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/TesteAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000..2b068d114
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/drawable/ic_launcher_background.xml b/TesteAndroid/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000..07d5da9cb
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TesteAndroid/app/src/main/res/drawable/ic_logout.xml b/TesteAndroid/app/src/main/res/drawable/ic_logout.xml
new file mode 100644
index 000000000..33ae72f7d
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/ic_logout.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/TesteAndroid/app/src/main/res/drawable/logo.xml b/TesteAndroid/app/src/main/res/drawable/logo.xml
new file mode 100644
index 000000000..f5711f8a4
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/logo.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/TesteAndroid/app/src/main/res/drawable/shape_button_blue.xml b/TesteAndroid/app/src/main/res/drawable/shape_button_blue.xml
new file mode 100644
index 000000000..96ad27bcc
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/shape_button_blue.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/drawable/shape_button_transparent.xml b/TesteAndroid/app/src/main/res/drawable/shape_button_transparent.xml
new file mode 100644
index 000000000..c451f3a55
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/shape_button_transparent.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/drawable/shape_divider_transparent.xml b/TesteAndroid/app/src/main/res/drawable/shape_divider_transparent.xml
new file mode 100644
index 000000000..d3ea7d7ca
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/shape_divider_transparent.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/drawable/shape_edit_text_gray_outline.xml b/TesteAndroid/app/src/main/res/drawable/shape_edit_text_gray_outline.xml
new file mode 100644
index 000000000..4e1808693
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/drawable/shape_edit_text_gray_outline.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/font/helvetica_neue.ttf b/TesteAndroid/app/src/main/res/font/helvetica_neue.ttf
new file mode 100644
index 000000000..cac3b75d8
Binary files /dev/null and b/TesteAndroid/app/src/main/res/font/helvetica_neue.ttf differ
diff --git a/TesteAndroid/app/src/main/res/font/helvetica_neue_light.ttf b/TesteAndroid/app/src/main/res/font/helvetica_neue_light.ttf
new file mode 100644
index 000000000..0bf4e61cc
Binary files /dev/null and b/TesteAndroid/app/src/main/res/font/helvetica_neue_light.ttf differ
diff --git a/TesteAndroid/app/src/main/res/layout/activity_login.xml b/TesteAndroid/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 000000000..0b5b1dbc0
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/layout/activity_main.xml b/TesteAndroid/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000..8c528e91c
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/layout/app_bar_custom.xml b/TesteAndroid/app/src/main/res/layout/app_bar_custom.xml
new file mode 100644
index 000000000..1e515b5d9
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/layout/app_bar_custom.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/layout/item_recycler_statement.xml b/TesteAndroid/app/src/main/res/layout/item_recycler_statement.xml
new file mode 100644
index 000000000..241b3f9cb
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/layout/item_recycler_statement.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000..eca70cfe5
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000..eca70cfe5
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher.png b/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..a571e6009
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..61da551c5
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher.png b/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c41dd2853
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..db5080a75
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..6dba46dab
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..da31a871c
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..15ac68172
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..b216f2d31
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..f25a41974
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..e96783ccc
Binary files /dev/null and b/TesteAndroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/TesteAndroid/app/src/main/res/values/colors.xml b/TesteAndroid/app/src/main/res/values/colors.xml
new file mode 100644
index 000000000..64e981395
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/values/colors.xml
@@ -0,0 +1,16 @@
+
+
+ #6200EE
+ #3700B3
+ #03DAC5
+ #FFFFFF
+ #DCE2EE
+ #A8B4C4
+ #485465
+ #8991f4
+ #4E5AEf
+ #3B48EE
+ #2932a6
+ #FF4C4C
+ #00000000
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/values/dimens.xml b/TesteAndroid/app/src/main/res/values/dimens.xml
new file mode 100644
index 000000000..09739f02c
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/values/dimens.xml
@@ -0,0 +1,41 @@
+
+
+ 33dp
+ 17dp
+ 14dp
+ 18dp
+ 17dp
+ 18dp
+
+ 42dp
+ 11dp
+ 15sp
+ 4dp
+ 1dp
+ 13dp
+ 12dp
+
+ 16sp
+ 77dp
+ 4dp
+ 80dp
+ 17dp
+
+ 17sp
+ 16sp
+ 16sp
+ 12sp
+ 20sp
+ 8dp
+
+ 25sp
+ 12sp
+
+ 15dp
+
+ 21dp
+ 6dp
+
+ 15dp
+ 5dp
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/values/strings.xml b/TesteAndroid/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000..6eab67aa8
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/values/strings.xml
@@ -0,0 +1,19 @@
+
+ TesteAndroid
+
+
+ Login
+ Logo
+ User
+ Password
+ Último login:
+ Login
+
+
+ Home
+ Conta
+ %s / %s
+ Saldo
+ Recentes
+ Logout
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/main/res/values/styles.xml b/TesteAndroid/app/src/main/res/values/styles.xml
new file mode 100644
index 000000000..f54a0982f
--- /dev/null
+++ b/TesteAndroid/app/src/main/res/values/styles.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FieldHelperUnitTest.java b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FieldHelperUnitTest.java
new file mode 100644
index 000000000..c35b1d290
--- /dev/null
+++ b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FieldHelperUnitTest.java
@@ -0,0 +1,75 @@
+package com.accenture.android.app.testeandroid;
+
+import com.accenture.android.app.testeandroid.helpers.FieldHelper;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class FieldHelperUnitTest {
+ @Test
+ public void formatCpf_isCorrect() {
+ assertTrue(FieldHelper.isCPF("667.625.580-46"));
+ assertTrue(FieldHelper.isCPF("27174627080"));
+ assertFalse(FieldHelper.isCPF(""));
+ assertFalse(FieldHelper.isCPF("271746270800"));
+ assertFalse(FieldHelper.isCPF("a"));
+ assertFalse(FieldHelper.isCPF("27174a2708a"));
+ }
+
+ @Test
+ public void formatEmail_isCorrect() {
+ assertTrue(FieldHelper.isEmail("asd@email.com"));
+ assertTrue(FieldHelper.isEmail("asd.fgh@email.com"));
+ assertTrue(FieldHelper.isEmail("asd-fgh@email.com"));
+ assertTrue(FieldHelper.isEmail("asd_fgh@email.com"));
+ assertTrue(FieldHelper.isEmail("asd.123@email.com"));
+ assertTrue(FieldHelper.isEmail("asd-123@email.com"));
+ assertTrue(FieldHelper.isEmail("asd_123@email.com"));
+ assertTrue(FieldHelper.isEmail("asd@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd.fgh@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd-fgh@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd_fgh@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd.123@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd-123@email.com.br"));
+ assertTrue(FieldHelper.isEmail("asd_123@email.com.br"));
+ assertFalse(FieldHelper.isEmail("asd@email.com.com.br"));
+ assertFalse(FieldHelper.isEmail("asd"));
+ assertFalse(FieldHelper.isEmail("@"));
+ assertFalse(FieldHelper.isEmail("."));
+ assertFalse(FieldHelper.isEmail("asd@"));
+ assertFalse(FieldHelper.isEmail("@asd"));
+ assertFalse(FieldHelper.isEmail("asd."));
+ assertFalse(FieldHelper.isEmail(".asd"));
+ assertFalse(FieldHelper.isEmail("asd@123.com"));
+ assertFalse(FieldHelper.isEmail("asd@email.123"));
+ }
+
+ @Test
+ public void formatPassword_isCorrect() {
+ assertTrue(FieldHelper.isPassword("A!0"));
+ assertTrue(FieldHelper.isPassword("!A0"));
+ assertTrue(FieldHelper.isPassword("!0A"));
+ assertTrue(FieldHelper.isPassword("0!A"));
+ assertTrue(FieldHelper.isPassword("c0!Ab"));
+ assertTrue(FieldHelper.isPassword("c0d!1Ab"));
+
+ assertFalse(FieldHelper.isPassword("123"));
+ assertFalse(FieldHelper.isPassword("ABC"));
+ assertFalse(FieldHelper.isPassword("abc"));
+ assertFalse(FieldHelper.isPassword("!@#"));
+ assertFalse(FieldHelper.isPassword("A1A"));
+ assertFalse(FieldHelper.isPassword("1A1"));
+ assertFalse(FieldHelper.isPassword("1!1"));
+ assertFalse(FieldHelper.isPassword("!1!"));
+ assertFalse(FieldHelper.isPassword("!A!"));
+ assertFalse(FieldHelper.isPassword("A!A"));
+ assertFalse(FieldHelper.isPassword(""));
+ assertFalse(FieldHelper.isPassword(" "));
+ }
+}
diff --git a/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FormatHelperUnitTest.java b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FormatHelperUnitTest.java
new file mode 100644
index 000000000..1b8dc7094
--- /dev/null
+++ b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/FormatHelperUnitTest.java
@@ -0,0 +1,48 @@
+package com.accenture.android.app.testeandroid;
+
+import com.accenture.android.app.testeandroid.helpers.FormatHelper;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class FormatHelperUnitTest {
+ @Test
+ public void formatarReal_isCorrect() {
+ assertEquals("R$ 0,00", FormatHelper.formatarReal(0.0));
+ assertEquals("R$ 1,00", FormatHelper.formatarReal(1.0));
+ assertEquals("-R$ 1,00", FormatHelper.formatarReal(-1.0));
+ assertEquals("R$ 10,00", FormatHelper.formatarReal(10.0));
+ assertEquals("-R$ 10,00", FormatHelper.formatarReal(-10.0));
+ assertEquals("R$ 100,00", FormatHelper.formatarReal(100.0));
+ assertEquals("-R$ 100,00", FormatHelper.formatarReal(-100.0));
+ assertEquals("R$ 1.000,00", FormatHelper.formatarReal(1000.0));
+ assertEquals("-R$ 1.000,00", FormatHelper.formatarReal(-1000.0));
+ }
+
+ @Test
+ public void formatarAgenciaBanco_isCorrect() {
+ assertEquals("01.234567-8", FormatHelper.formatarAgenciaBanco("012345678"));
+ assertEquals("00.234567-8", FormatHelper.formatarAgenciaBanco("002345678"));
+ assertEquals("00.034567-8", FormatHelper.formatarAgenciaBanco("000345678"));
+ assertEquals("00.004567-8", FormatHelper.formatarAgenciaBanco("000045678"));
+ assertEquals("00.000567-8", FormatHelper.formatarAgenciaBanco("000005678"));
+ assertEquals("00.000067-8", FormatHelper.formatarAgenciaBanco("000000678"));
+ assertEquals("00.000007-8", FormatHelper.formatarAgenciaBanco("000000078"));
+ assertEquals("00.000000-8", FormatHelper.formatarAgenciaBanco("000000008"));
+ assertEquals("00.000000-0", FormatHelper.formatarAgenciaBanco("000000000"));
+ assertEquals("01.234567-8", FormatHelper.formatarAgenciaBanco("12345678"));
+ assertEquals("00.234567-8", FormatHelper.formatarAgenciaBanco("2345678"));
+ assertEquals("00.034567-8", FormatHelper.formatarAgenciaBanco("345678"));
+ assertEquals("00.004567-8", FormatHelper.formatarAgenciaBanco("45678"));
+ assertEquals("00.000567-8", FormatHelper.formatarAgenciaBanco("5678"));
+ assertEquals("00.000067-8", FormatHelper.formatarAgenciaBanco("678"));
+ assertEquals("00.000007-8", FormatHelper.formatarAgenciaBanco("78"));
+ assertEquals("00.000000-8", FormatHelper.formatarAgenciaBanco("8"));
+ assertEquals("00.000000-0", FormatHelper.formatarAgenciaBanco(""));
+ }
+}
diff --git a/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/StatementConverterUnitTest.java b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/StatementConverterUnitTest.java
new file mode 100644
index 000000000..c315526e6
--- /dev/null
+++ b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/StatementConverterUnitTest.java
@@ -0,0 +1,69 @@
+package com.accenture.android.app.testeandroid;
+
+import com.accenture.android.app.testeandroid.data.converters.StatementConverter;
+import com.accenture.android.app.testeandroid.data.http.responses.StatementResponse;
+import com.accenture.android.app.testeandroid.domain.Statement;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class StatementConverterUnitTest {
+ private final StatementResponse.StatementData statementDataResponse;
+ private final StatementResponse.StatementData statementDataResponseNull;
+ private final List statementDataResponses;
+
+ private final static String TITLE = "Título";
+ private final static String DESC = "Descrição";
+ private final static Double VALUE = 1000.0;
+ private final static String DATE = "2020-06-10";
+
+ public StatementConverterUnitTest() {
+ this.statementDataResponse = new StatementResponse.StatementData(TITLE, DESC, DATE, VALUE);
+ this.statementDataResponseNull = new StatementResponse.StatementData();
+
+ this.statementDataResponses = new ArrayList<>();
+ this.statementDataResponses.add(this.statementDataResponse);
+ this.statementDataResponses.add(this.statementDataResponseNull);
+ }
+
+ @Test
+ public void toDomain_isCorrect() {
+ Statement statement = StatementConverter.toDomain(this.statementDataResponse);
+
+ assertEquals(TITLE, statement.getTitle());
+ assertEquals(DESC, statement.getDesc());
+ assertEquals(VALUE, statement.getValue());
+ assertEquals(DATE, statement.getDate());
+
+ statement = StatementConverter.toDomain(this.statementDataResponseNull);
+ assertEquals("", statement.getTitle());
+ assertEquals("", statement.getDesc());
+ assertEquals(new Double(0), statement.getValue());
+ assertEquals("", statement.getDate());
+ }
+
+ @Test
+ public void toDomainList_isCorrect() {
+ List statements = StatementConverter.toDomain(this.statementDataResponses);
+
+ assertEquals(2, statements.size());
+
+ assertEquals(TITLE, statements.get(0).getTitle());
+ assertEquals(DESC, statements.get(0).getDesc());
+ assertEquals(VALUE, statements.get(0).getValue());
+ assertEquals(DATE, statements.get(0).getDate());
+
+ assertEquals("", statements.get(1).getTitle());
+ assertEquals("", statements.get(1).getDesc());
+ assertEquals(new Double(0), statements.get(1).getValue());
+ assertEquals("", statements.get(1).getDate());
+ }
+}
diff --git a/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/TestSuite.java b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/TestSuite.java
new file mode 100644
index 000000000..616a050f5
--- /dev/null
+++ b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/TestSuite.java
@@ -0,0 +1,18 @@
+package com.accenture.android.app.testeandroid;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ FieldHelperUnitTest.class,
+ FormatHelperUnitTest.class,
+ StatementConverterUnitTest.class,
+ UserAccountConverterUnitTest.class
+})
+public class TestSuite {
+}
diff --git a/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/UserAccountConverterUnitTest.java b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/UserAccountConverterUnitTest.java
new file mode 100644
index 000000000..78b4cefbc
--- /dev/null
+++ b/TesteAndroid/app/src/test/java/com/accenture/android/app/testeandroid/UserAccountConverterUnitTest.java
@@ -0,0 +1,47 @@
+package com.accenture.android.app.testeandroid;
+
+import com.accenture.android.app.testeandroid.data.converters.UserAccountConverter;
+import com.accenture.android.app.testeandroid.data.http.responses.UserAccountResponse;
+import com.accenture.android.app.testeandroid.domain.UserAccount;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Created by Denis Magno on 10/07/2020.
+ * denis_magno16@hotmail.com
+ */
+public class UserAccountConverterUnitTest {
+ private final UserAccountResponse.UserAccountData userAccountDataResponse;
+ private final UserAccountResponse.UserAccountData userAccountDataResponseNull;
+
+ private final static Long ID = 1L;
+ private final static String NAME = "Nome";
+ private final static String BANK_ACCOUNT = "012345678";
+ private final static String AGENCY = "2020";
+ private final static Double BALANCE = 1.2345;
+
+ public UserAccountConverterUnitTest() {
+ this.userAccountDataResponse = new UserAccountResponse.UserAccountData(ID, NAME, BANK_ACCOUNT, AGENCY, BALANCE);
+ this.userAccountDataResponseNull = new UserAccountResponse.UserAccountData();
+ }
+
+ @Test
+ public void toDomain_isCorrect() {
+ UserAccount statement = UserAccountConverter.toDomain(this.userAccountDataResponse);
+
+ assertEquals(ID, statement.getUserId());
+ assertEquals(NAME, statement.getName());
+ assertEquals(BANK_ACCOUNT, statement.getBankAccount());
+ assertEquals(AGENCY, statement.getAgency());
+ assertEquals(BALANCE, statement.getBalance());
+
+ statement = UserAccountConverter.toDomain(this.userAccountDataResponseNull);
+ assertEquals(new Long(0), statement.getUserId());
+ assertEquals("", statement.getName());
+ assertEquals("", statement.getBankAccount());
+ assertEquals("", statement.getAgency());
+ assertEquals(new Double(0), statement.getBalance());
+ }
+}
diff --git a/TesteAndroid/build.gradle b/TesteAndroid/build.gradle
new file mode 100644
index 000000000..da807a2e5
--- /dev/null
+++ b/TesteAndroid/build.gradle
@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.0.0"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/TesteAndroid/gradle.properties b/TesteAndroid/gradle.properties
new file mode 100644
index 000000000..c52ac9b79
--- /dev/null
+++ b/TesteAndroid/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
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
\ No newline at end of file
diff --git a/TesteAndroid/gradle/wrapper/gradle-wrapper.jar b/TesteAndroid/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..f6b961fd5
Binary files /dev/null and b/TesteAndroid/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/TesteAndroid/gradle/wrapper/gradle-wrapper.properties b/TesteAndroid/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..3009951ac
--- /dev/null
+++ b/TesteAndroid/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jul 09 14:52:38 BRT 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/TesteAndroid/gradlew b/TesteAndroid/gradlew
new file mode 100644
index 000000000..cccdd3d51
--- /dev/null
+++ b/TesteAndroid/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/TesteAndroid/gradlew.bat b/TesteAndroid/gradlew.bat
new file mode 100644
index 000000000..f9553162f
--- /dev/null
+++ b/TesteAndroid/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/TesteAndroid/settings.gradle b/TesteAndroid/settings.gradle
new file mode 100644
index 000000000..c95df0609
--- /dev/null
+++ b/TesteAndroid/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name = "TesteAndroid"
\ No newline at end of file
diff --git a/login_print.png b/login_print.png
new file mode 100644
index 000000000..63e79d3b6
Binary files /dev/null and b/login_print.png differ
diff --git a/logout_print.png b/logout_print.png
new file mode 100644
index 000000000..efdd6027e
Binary files /dev/null and b/logout_print.png differ