├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── kotlin │ │ └── com │ │ └── fernandocejas │ │ └── android │ │ └── sample │ │ └── ui │ │ ├── HelloWorldActivityTest.kt │ │ ├── MainActivityTest.kt │ │ └── framework │ │ ├── AcceptanceTest.kt │ │ ├── Events.kt │ │ └── Matchers.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── fernandocejas │ │ │ └── android │ │ │ └── sample │ │ │ ├── executor │ │ │ ├── PostExecutionThread.java │ │ │ └── ThreadExecutor.java │ │ │ ├── io │ │ │ ├── FileManager.java │ │ │ └── Serializer.java │ │ │ ├── ui │ │ │ ├── HelloWorldActivity.java │ │ │ └── MainActivity.java │ │ │ └── users │ │ │ ├── GetUserDetails.java │ │ │ ├── User.java │ │ │ ├── UserEntity.java │ │ │ └── UserRepository.java │ └── res │ │ ├── layout │ │ ├── activity_hello_world.xml │ │ ├── activity_main.xml │ │ ├── content_hello_world.xml │ │ └── content_main.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── kotlin │ └── com │ └── fernandocejas │ └── android │ └── sample │ ├── AndroidTest.kt │ ├── io │ ├── FileManagerTest.kt │ └── SerializerTest.kt │ └── users │ └── GetUserDetailsTest.kt ├── build.gradle ├── buildsystem └── debug.keystore ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail db 2 | Thumbs.db 3 | 4 | # OSX files 5 | .DS_Store 6 | 7 | # built application files 8 | *.apk 9 | *.ap_ 10 | 11 | # files for the dex VM 12 | *.dex 13 | 14 | # Java class files 15 | *.class 16 | 17 | # generated files 18 | bin/ 19 | gen/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Eclipse project files 26 | .classpath 27 | .project 28 | 29 | # Android Studio 30 | .idea 31 | .gradle 32 | /*/local.properties 33 | /*/out 34 | /*/*/build 35 | build 36 | /*/*/production 37 | *.iml 38 | *.iws 39 | *.ipr 40 | *~ 41 | *.swp 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Android-KotlinInTests 2 | ========================= 3 | 4 | This is a sample app that is part of blog posts I have written about how to test android applications using Kotlin. 5 | 6 | [Android Testing with Kotlin](http://fernandocejas.com/2017/02/03/android-testing-with-kotlin/) 7 | 8 | 9 | ## Local Development 10 | 11 | Here are some useful Gradle/adb commands for executing this example: 12 | 13 | * `./gradlew clean build` - Build the entire example and execute unit and integration tests plus lint check. 14 | * `./gradlew runUnitTests` - Execute both unit and integration tests. 15 | * `./gradlew runAcceptanceTests` - Execute espresso and instrumentation acceptance tests. 16 | 17 | 18 | 19 | ## Code style 20 | 21 | Here you can download and install the java codestyle. 22 | https://github.com/android10/java-code-styles 23 | 24 | 25 | ## License 26 | 27 | Copyright 2018 Fernando Cejas 28 | 29 | Licensed under the Apache License, Version 2.0 (the "License"); 30 | you may not use this file except in compliance with the License. 31 | You may obtain a copy of the License at 32 | 33 | http://www.apache.org/licenses/LICENSE-2.0 34 | 35 | Unless required by applicable law or agreed to in writing, software 36 | distributed under the License is distributed on an "AS IS" BASIS, 37 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 38 | See the License for the specific language governing permissions and 39 | limitations under the License. 40 | 41 | 42 | ![http://www.fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 43 | 44 | Buy Me A Coffee 45 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.5-2' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.application' 12 | apply plugin: 'kotlin-android' 13 | 14 | android { 15 | compileSdkVersion 25 16 | buildToolsVersion '25.0.2' 17 | 18 | defaultConfig { 19 | applicationId 'com.fernandocejas.android.sample' 20 | minSdkVersion 15 21 | targetSdkVersion 25 22 | versionCode 1 23 | versionName "1.0" 24 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' 25 | } 26 | 27 | sourceSets { 28 | //Dedicated directories for tests written in Kotlin 29 | test.java.srcDirs += 'src/test/kotlin' 30 | androidTest.java.srcDirs += 'src/androidTest/kotlin' 31 | } 32 | 33 | packagingOptions { 34 | exclude 'LICENSE.txt' 35 | exclude 'META-INF/DEPENDENCIES' 36 | exclude 'META-INF/ASL2.0' 37 | exclude 'META-INF/NOTICE' 38 | exclude 'META-INF/LICENSE' 39 | } 40 | 41 | lintOptions { 42 | quiet true 43 | abortOnError false 44 | ignoreWarnings true 45 | disable 'InvalidPackage' //Some libraries have issues with this. 46 | disable 'OldTargetApi' //Lint gives this warning but SDK 20 would be Android L Beta. 47 | disable 'IconDensities' //For testing purpose. This is safe to remove. 48 | disable 'IconMissingDensityFolder' //For testing purpose. This is safe to remove. 49 | } 50 | 51 | signingConfigs { 52 | debug { 53 | storeFile file('../buildsystem/debug.keystore') 54 | storePassword 'android' 55 | keyAlias 'androiddebugkey' 56 | keyPassword 'android' 57 | } 58 | } 59 | 60 | buildTypes { 61 | debug { 62 | signingConfig signingConfigs.debug 63 | } 64 | } 65 | } 66 | 67 | //Ensure Kotlin will not be used in production code. 68 | afterEvaluate { 69 | android.sourceSets.all { sourceSet -> 70 | if (!sourceSet.name.startsWith('test') || !sourceSet.name.startsWith('androidTest')) { 71 | sourceSet.kotlin.setSrcDirs([]) 72 | } 73 | } 74 | } 75 | 76 | dependencies { 77 | compile 'io.reactivex.rxjava2:rxjava:2.0.2' 78 | compile 'com.google.code.gson:gson:2.4' 79 | compile 'com.android.support:appcompat-v7:25.1.0' 80 | compile 'com.android.support:design:25.1.0' 81 | compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.6" 82 | 83 | testCompile 'junit:junit:4.12' 84 | testCompile "org.robolectric:robolectric:3.2.1" 85 | testCompile 'org.jetbrains.kotlin:kotlin-stdlib:1.0.6' 86 | testCompile 'org.jetbrains.kotlin:kotlin-test-junit:1.0.6' 87 | testCompile "com.nhaarman:mockito-kotlin:1.1.0" 88 | testCompile 'org.amshove.kluent:kluent:1.14' 89 | 90 | androidTestCompile 'com.android.support.test:runner:0.5' 91 | androidTestCompile 'com.android.support.test:rules:0.5' 92 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' 93 | androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2' 94 | androidTestCompile 'com.android.support:support-annotations:25.1.0' 95 | } 96 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/23.0.2/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/kotlin/com/fernandocejas/android/sample/ui/HelloWorldActivityTest.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui 17 | 18 | import com.fernandocejas.android.sample.R 19 | import com.fernandocejas.android.sample.ui.framework.AcceptanceTest 20 | import org.junit.Test 21 | 22 | class HelloWorldActivityTest : AcceptanceTest(HelloWorldActivity::class.java) { 23 | 24 | @Test 25 | fun shouldSayHelloWorld() { 26 | checkThat.viewContainsText(R.id.hello, R.string.hello) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/androidTest/kotlin/com/fernandocejas/android/sample/ui/MainActivityTest.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui 17 | 18 | import com.fernandocejas.android.sample.R 19 | import com.fernandocejas.android.sample.ui.framework.AcceptanceTest 20 | import org.junit.Test 21 | 22 | class MainActivityTest : AcceptanceTest(MainActivity::class.java) { 23 | 24 | @Test 25 | fun shouldOpenHelloWorldScreen() { 26 | events.clickOnView(R.id.btn_hello_world) 27 | checkThat.nextOpenActivityIs(HelloWorldActivity::class.java) 28 | } 29 | 30 | @Test 31 | fun shouldDisplayAction() { 32 | events.clickOnView(R.id.fab) 33 | checkThat.viewIsVisibleAndContainsText(R.string.action) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/androidTest/kotlin/com/fernandocejas/android/sample/ui/framework/AcceptanceTest.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui.framework 17 | 18 | import android.app.Activity 19 | import android.support.test.espresso.intent.rule.IntentsTestRule 20 | import android.support.test.filters.LargeTest 21 | import android.support.test.rule.ActivityTestRule 22 | import android.support.test.runner.AndroidJUnit4 23 | import org.junit.Rule 24 | import org.junit.runner.RunWith 25 | 26 | @LargeTest 27 | @RunWith(AndroidJUnit4::class) 28 | abstract class AcceptanceTest(clazz: Class) { 29 | 30 | @Rule @JvmField 31 | val testRule: ActivityTestRule = IntentsTestRule(clazz) 32 | 33 | val checkThat: Matchers = Matchers() 34 | val events: Events = Events() 35 | } 36 | 37 | -------------------------------------------------------------------------------- /app/src/androidTest/kotlin/com/fernandocejas/android/sample/ui/framework/Events.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui.framework 17 | 18 | import android.support.annotation.IdRes 19 | import android.support.test.espresso.Espresso.onView 20 | import android.support.test.espresso.action.ViewActions.click 21 | import android.support.test.espresso.matcher.ViewMatchers.withId 22 | 23 | class Events { 24 | fun clickOnView(@IdRes viewId: Int) { 25 | onView(withId(viewId)).perform(click()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/androidTest/kotlin/com/fernandocejas/android/sample/ui/framework/Matchers.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui.framework 17 | 18 | import android.app.Activity 19 | import android.support.annotation.IdRes 20 | import android.support.annotation.StringRes 21 | import android.support.test.espresso.Espresso.onView 22 | import android.support.test.espresso.assertion.ViewAssertions.matches 23 | import android.support.test.espresso.intent.Intents.intended 24 | import android.support.test.espresso.intent.matcher.IntentMatchers 25 | import android.support.test.espresso.matcher.ViewMatchers.* 26 | 27 | class Matchers { 28 | fun nextOpenActivityIs(clazz: Class) { 29 | intended(IntentMatchers.hasComponent(clazz.name)) 30 | } 31 | 32 | fun viewIsVisibleAndContainsText(@StringRes stringResource: Int) { 33 | onView(withText(stringResource)).check(matches(withEffectiveVisibility(Visibility.VISIBLE))) 34 | } 35 | 36 | fun viewContainsText(@IdRes viewId: Int, @StringRes stringResource: Int) { 37 | onView(withId(viewId)).check(matches(withText(stringResource))) 38 | } 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/executor/PostExecutionThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.executor; 17 | 18 | import io.reactivex.Scheduler; 19 | 20 | /** 21 | * Thread abstraction created to change the execution context from any thread to any other thread. 22 | * Useful to encapsulate a UI Thread for example, since some job will be done in background, an 23 | * implementation of this interface will change context and update the UI. 24 | */ 25 | public abstract class PostExecutionThread { 26 | public abstract Scheduler getScheduler(); 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/executor/ThreadExecutor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.executor; 17 | 18 | import java.util.concurrent.Executor; 19 | 20 | /** 21 | * Executor implementation can be based on different frameworks or techniques 22 | * of asynchronous execution. 23 | */ 24 | public interface ThreadExecutor extends Executor {} 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/io/FileManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.io; 17 | 18 | import android.content.Context; 19 | import android.content.SharedPreferences; 20 | 21 | import java.io.BufferedReader; 22 | import java.io.File; 23 | import java.io.FileReader; 24 | import java.io.FileWriter; 25 | import java.io.IOException; 26 | 27 | /** 28 | * Helper class to do operations on regular files/directories. 29 | */ 30 | public class FileManager { 31 | 32 | FileManager() {} 33 | 34 | /** 35 | * Writes a file to Disk. 36 | * This is an I/O operation and this method executes in the main thread, so it is recommended to 37 | * perform this operation using another thread. 38 | * 39 | * @param file The file to write to Disk. 40 | */ 41 | void writeToFile(File file, String fileContent) { 42 | if (!file.exists()) { 43 | try { 44 | final FileWriter writer = new FileWriter(file); 45 | writer.write(fileContent); 46 | writer.close(); 47 | } catch (IOException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * Reads a content from a file. 55 | * This is an I/O operation and this method executes in the main thread, so it is recommended to 56 | * perform the operation using another thread. 57 | * 58 | * @param file The file to read from. 59 | * @return A string with the content of the file. 60 | */ 61 | String readFileContent(File file) { 62 | final StringBuilder fileContentBuilder = new StringBuilder(); 63 | if (file.exists()) { 64 | String stringLine; 65 | try { 66 | final FileReader fileReader = new FileReader(file); 67 | final BufferedReader bufferedReader = new BufferedReader(fileReader); 68 | while ((stringLine = bufferedReader.readLine()) != null) { 69 | fileContentBuilder.append(stringLine).append("\n"); 70 | } 71 | bufferedReader.close(); 72 | fileReader.close(); 73 | } catch (IOException e) { 74 | e.printStackTrace(); 75 | } 76 | } 77 | return fileContentBuilder.toString(); 78 | } 79 | 80 | /** 81 | * Returns a boolean indicating whether this file can be found on the underlying file system. 82 | * 83 | * @param file The file to check existence. 84 | * @return true if this file exists, false otherwise. 85 | */ 86 | boolean exists(File file) { 87 | return file.exists(); 88 | } 89 | 90 | /** 91 | * Warning: Deletes the content of a directory. 92 | * This is an I/O operation and this method executes in the main thread, so it is recommended to 93 | * perform the operation using another thread. 94 | * 95 | * @param directory The directory which its content will be deleted. 96 | */ 97 | boolean clearDirectory(File directory) { 98 | boolean result = false; 99 | if (directory.exists()) { 100 | for (File file : directory.listFiles()) { 101 | result = file.delete(); 102 | } 103 | } 104 | return result; 105 | } 106 | 107 | /** 108 | * Write a value to a user preferences file. 109 | * 110 | * @param context {@link android.content.Context} to retrieve android user preferences. 111 | * @param preferenceFileName A file name reprensenting where data will be written to. 112 | * @param key A string for the key that will be used to retrieve the value in the future. 113 | * @param value A long representing the value to be inserted. 114 | */ 115 | void writeToPreferences(Context context, String preferenceFileName, String key, 116 | long value) { 117 | 118 | final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName, 119 | Context.MODE_PRIVATE); 120 | final SharedPreferences.Editor editor = sharedPreferences.edit(); 121 | editor.putLong(key, value); 122 | editor.apply(); 123 | } 124 | 125 | /** 126 | * Get a value from a user preferences file. 127 | * 128 | * @param context {@link android.content.Context} to retrieve android user preferences. 129 | * @param preferenceFileName A file name representing where data will be get from. 130 | * @param key A key that will be used to retrieve the value from the preference file. 131 | * @return A long representing the value retrieved from the preferences file. 132 | */ 133 | long getFromPreferences(Context context, String preferenceFileName, String key) { 134 | final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName, 135 | Context.MODE_PRIVATE); 136 | return sharedPreferences.getLong(key, 0); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/io/Serializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.io; 17 | 18 | import com.google.gson.Gson; 19 | 20 | /** 21 | * Json Serializer/Deserializer. 22 | */ 23 | public class Serializer { 24 | 25 | private final Gson gson = new Gson(); 26 | 27 | Serializer() {} 28 | 29 | /** 30 | * Serialize an object to Json. 31 | * 32 | * @param object to serialize. 33 | */ 34 | public String serialize(Object object, Class clazz) { 35 | return gson.toJson(object, clazz); 36 | } 37 | 38 | /** 39 | * Deserialize a json representation of an object. 40 | * 41 | * @param string A json string to deserialize. 42 | */ 43 | public T deserialize(String string, Class clazz) { 44 | return gson.fromJson(string, clazz); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/ui/HelloWorldActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui; 17 | 18 | import android.os.Bundle; 19 | import android.support.v7.app.AppCompatActivity; 20 | import android.support.v7.widget.Toolbar; 21 | import com.fernandocejas.android.sample.R; 22 | 23 | public class HelloWorldActivity extends AppCompatActivity { 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_hello_world); 29 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 30 | setSupportActionBar(toolbar); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.ui; 17 | 18 | import android.content.Intent; 19 | import android.os.Bundle; 20 | import android.support.design.widget.FloatingActionButton; 21 | import android.support.design.widget.Snackbar; 22 | import android.support.v7.app.AppCompatActivity; 23 | import android.support.v7.widget.Toolbar; 24 | import android.view.Menu; 25 | import android.view.MenuItem; 26 | import android.view.View; 27 | import android.widget.Button; 28 | import com.fernandocejas.android.sample.R; 29 | 30 | public class MainActivity extends AppCompatActivity { 31 | 32 | @Override 33 | public boolean onCreateOptionsMenu(Menu menu) { 34 | getMenuInflater().inflate(R.menu.menu_main, menu); 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean onOptionsItemSelected(MenuItem item) { 40 | int id = item.getItemId(); 41 | //noinspection SimplifiableIfStatement 42 | if (id == R.id.action_settings) { 43 | return true; 44 | } 45 | return super.onOptionsItemSelected(item); 46 | } 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | setContentView(R.layout.activity_main); 52 | 53 | //Toolbar 54 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 55 | setSupportActionBar(toolbar); 56 | 57 | //Floating button 58 | final FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab); 59 | floatingActionButton.setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View view) { 62 | Snackbar.make(view, R.string.action, Snackbar.LENGTH_LONG) 63 | .setAction("Action", null).show(); 64 | } 65 | }); 66 | 67 | //Hello world button 68 | final Button helloWorldButton = (Button) findViewById(R.id.btn_hello_world); 69 | helloWorldButton.setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View view) { 72 | startActivity(new Intent(MainActivity.this, HelloWorldActivity.class)); 73 | } 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/users/GetUserDetails.java: -------------------------------------------------------------------------------- 1 | package com.fernandocejas.android.sample.users; 2 | 3 | import com.fernandocejas.android.sample.executor.PostExecutionThread; 4 | import com.fernandocejas.android.sample.executor.ThreadExecutor; 5 | import io.reactivex.Observable; 6 | 7 | /** 8 | * Copyright (C) 2017 android10.org Open Source Project 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | */ 22 | public class GetUserDetails { 23 | 24 | private final UserRepository userRepository; 25 | private final ThreadExecutor threadExecutor; 26 | private final PostExecutionThread postExecutionThread; 27 | 28 | GetUserDetails(UserRepository userRepository, ThreadExecutor threadExecutor, 29 | PostExecutionThread postExecutionThread) { 30 | this.userRepository = userRepository; 31 | this.threadExecutor = threadExecutor; 32 | this.postExecutionThread = postExecutionThread; 33 | } 34 | 35 | Observable buildUseCaseObservable(Params params) { 36 | return this.userRepository.user(params.userId); 37 | } 38 | 39 | static final class Params { 40 | 41 | private final int userId; 42 | 43 | private Params(int userId) { 44 | this.userId = userId; 45 | } 46 | 47 | public static Params forUser(int userId) { 48 | return new Params(userId); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/users/User.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.users; 17 | 18 | /** 19 | * Class that represents a User in the domain layer. 20 | */ 21 | public class User { 22 | 23 | private final int userId; 24 | 25 | public User(int userId) { 26 | this.userId = userId; 27 | } 28 | 29 | private String coverUrl; 30 | private String fullName; 31 | private String email; 32 | private String description; 33 | private int followers; 34 | 35 | public int getUserId() { 36 | return userId; 37 | } 38 | 39 | public String getCoverUrl() { 40 | return coverUrl; 41 | } 42 | 43 | public void setCoverUrl(String coverUrl) { 44 | this.coverUrl = coverUrl; 45 | } 46 | 47 | public String getFullName() { 48 | return fullName; 49 | } 50 | 51 | public void setFullName(String fullName) { 52 | this.fullName = fullName; 53 | } 54 | 55 | public String getEmail() { 56 | return email; 57 | } 58 | 59 | public void setEmail(String email) { 60 | this.email = email; 61 | } 62 | 63 | public String getDescription() { 64 | return description; 65 | } 66 | 67 | public void setDescription(String description) { 68 | this.description = description; 69 | } 70 | 71 | public int getFollowers() { 72 | return followers; 73 | } 74 | 75 | public void setFollowers(int followers) { 76 | this.followers = followers; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/users/UserEntity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2017 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.users; 17 | 18 | import com.google.gson.annotations.SerializedName; 19 | 20 | /** 21 | * User Entity used in the data layer. 22 | */ 23 | public class UserEntity { 24 | 25 | @SerializedName("id") 26 | private int userId; 27 | 28 | @SerializedName("cover_url") 29 | private String coverUrl; 30 | 31 | @SerializedName("full_name") 32 | private String fullname; 33 | 34 | @SerializedName("description") 35 | private String description; 36 | 37 | @SerializedName("followers") 38 | private int followers; 39 | 40 | @SerializedName("email") 41 | private String email; 42 | 43 | public UserEntity() { 44 | //empty 45 | } 46 | 47 | public int getUserId() { 48 | return userId; 49 | } 50 | 51 | public void setUserId(int userId) { 52 | this.userId = userId; 53 | } 54 | 55 | public String getCoverUrl() { 56 | return coverUrl; 57 | } 58 | 59 | public String getFullname() { 60 | return fullname; 61 | } 62 | 63 | public void setFullname(String fullname) { 64 | this.fullname = fullname; 65 | } 66 | 67 | public String getDescription() { 68 | return description; 69 | } 70 | 71 | public int getFollowers() { 72 | return followers; 73 | } 74 | 75 | public String getEmail() { 76 | return email; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/fernandocejas/android/sample/users/UserRepository.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.android.sample.users; 17 | 18 | import io.reactivex.Observable; 19 | import java.util.List; 20 | 21 | /** 22 | * Interface that represents a Repository for getting {@link User} related data. 23 | */ 24 | public interface UserRepository { 25 | /** 26 | * Get an {@link Observable} which will emit a List of {@link User}. 27 | */ 28 | Observable> users(); 29 | 30 | /** 31 | * Get an {@link Observable} which will emit a {@link User}. 32 | * 33 | * @param userId The user id used to retrieve user data. 34 | */ 35 | Observable user(final int userId); 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_hello_world.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_hello_world.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 22 | 23 |