├── crashlytics_release_notes.txt
├── settings.gradle
├── app
├── .gitignore
├── fabric.properties
├── keystore
│ └── debug.keystore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── dimens.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ └── layout
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── item_ribot.xml
│ │ ├── java
│ │ │ └── be
│ │ │ │ └── neodigi
│ │ │ │ └── androidboilerplate
│ │ │ │ ├── injection
│ │ │ │ ├── ActivityContext.java
│ │ │ │ ├── ApplicationContext.java
│ │ │ │ ├── scope
│ │ │ │ │ └── PerActivity.java
│ │ │ │ ├── ConfigPersistent.java
│ │ │ │ ├── component
│ │ │ │ │ ├── ActivityComponent.java
│ │ │ │ │ ├── ConfigPersistentComponent.java
│ │ │ │ │ └── ApplicationComponent.java
│ │ │ │ └── module
│ │ │ │ │ ├── ActivityModule.java
│ │ │ │ │ ├── ApplicationModule.java
│ │ │ │ │ └── RestModule.java
│ │ │ │ ├── util
│ │ │ │ ├── RxUtil.java
│ │ │ │ ├── ViewUtil.java
│ │ │ │ ├── NetworkUtil.java
│ │ │ │ ├── AndroidComponentUtil.java
│ │ │ │ ├── RxEventBus.java
│ │ │ │ └── DialogFactory.java
│ │ │ │ ├── data
│ │ │ │ ├── remote
│ │ │ │ │ └── RestService.java
│ │ │ │ ├── local
│ │ │ │ │ ├── PreferencesHelper.java
│ │ │ │ │ └── DatabaseHelper.java
│ │ │ │ ├── model
│ │ │ │ │ └── User.java
│ │ │ │ ├── DataManager.java
│ │ │ │ └── SyncService.java
│ │ │ │ ├── ui
│ │ │ │ ├── base
│ │ │ │ │ ├── Presenter.java
│ │ │ │ │ ├── MvpView.java
│ │ │ │ │ ├── BasePresenter.java
│ │ │ │ │ └── BaseActivity.java
│ │ │ │ └── main
│ │ │ │ │ ├── MainMvpView.java
│ │ │ │ │ ├── UsersAdapter.java
│ │ │ │ │ ├── MainPresenter.java
│ │ │ │ │ └── MainActivity.java
│ │ │ │ └── BoilerplateApplication.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── be
│ │ │ └── neodigi
│ │ │ └── androidboilerplate
│ │ │ ├── util
│ │ │ ├── DefaultConfig.java
│ │ │ ├── RxEventBusTest.java
│ │ │ └── RxSchedulersOverrideRule.java
│ │ │ ├── DatabaseHelperTest.java
│ │ │ ├── MainPresenterTest.java
│ │ │ └── DataManagerTest.java
│ ├── debug
│ │ └── AndroidManifest.xml
│ ├── commonTest
│ │ └── java
│ │ │ └── be
│ │ │ └── neodigi
│ │ │ └── androidboilerplate
│ │ │ └── test
│ │ │ └── common
│ │ │ ├── injection
│ │ │ ├── component
│ │ │ │ └── TestComponent.java
│ │ │ └── module
│ │ │ │ └── ApplicationTestModule.java
│ │ │ ├── TestDataFactory.java
│ │ │ └── TestComponentRule.java
│ └── androidTest
│ │ └── java
│ │ └── be
│ │ └── neodigi
│ │ └── androidboilerplate
│ │ ├── runner
│ │ ├── RxAndroidJUnitRunner.java
│ │ └── UnlockDeviceAndroidJUnitRunner.java
│ │ ├── util
│ │ ├── RxIdlingExecutionHook.java
│ │ └── RxIdlingResource.java
│ │ └── MainActivityTest.java
├── proguard-rules.pro
└── build.gradle
├── images
└── check-task-diagram.png
├── .gitignore
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── config
└── quality
│ ├── findbugs
│ └── android-exclude-filter.xml
│ ├── pmd
│ └── pmd-ruleset.xml
│ ├── quality.gradle
│ └── checkstyle
│ └── checkstyle-config.xml
├── gradlew.bat
├── gradlew
├── README.md
└── LICENSE
/crashlytics_release_notes.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | *iml
3 | *.iml
4 | .idea
--------------------------------------------------------------------------------
/app/fabric.properties:
--------------------------------------------------------------------------------
1 | apiSecret=changeMeToYourRealApiSecret
2 | apiKey=changeMeToYourRealApiKey
--------------------------------------------------------------------------------
/app/keystore/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/app/keystore/debug.keystore
--------------------------------------------------------------------------------
/images/check-task-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/images/check-task-diagram.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | .DS_Store
5 | /build
6 | .idea/
7 | *iml
8 | *.iml
9 | */build
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 | # Gradle performance variables
3 | org.gradle.jvmargs=-Xmx4G -XX:MaxPermSize=512m
4 | org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NeoDigi/android-boilerplate/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #222222
4 | #000000
5 | #FFFFFF
6 | #ffdfdfdf
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 29 15:33:35 CEST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/test/java/be/neodigi/androidboilerplate/util/DefaultConfig.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | /**
4 | * Robolectric default config properties
5 | */
6 | public class DefaultConfig {
7 | //The api level that Roboelectric will use to run the unit tests
8 | public static final int EMULATE_SDK = 23;
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/ActivityContext.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Qualifier;
7 |
8 | @Qualifier
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface ActivityContext {
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/ApplicationContext.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Qualifier;
7 |
8 | @Qualifier
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface ApplicationContext {
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/util/RxUtil.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import rx.Subscription;
4 |
5 | public class RxUtil {
6 |
7 | public static void unsubscribe(Subscription subscription) {
8 | if (subscription != null && !subscription.isUnsubscribed()) {
9 | subscription.unsubscribe();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/data/remote/RestService.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.data.remote;
2 |
3 | import java.util.List;
4 |
5 | import be.neodigi.androidboilerplate.data.model.User;
6 | import retrofit2.http.GET;
7 | import rx.Observable;
8 |
9 | public interface RestService {
10 |
11 | @GET("users")
12 | Observable> getUsers();
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/ui/base/Presenter.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.ui.base;
2 |
3 | /**
4 | * Every presenter in the app must either implement this interface or extend BasePresenter
5 | * indicating the MvpView type that wants to be attached with.
6 | */
7 | public interface Presenter {
8 |
9 | void attachView(V mvpView);
10 |
11 | void detachView();
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/ui/base/MvpView.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.ui.base;
2 |
3 |
4 | /**
5 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter)
6 | * pattern must implement. Generally this interface will be extended by a more specific interface
7 | * that then usually will be implemented by an Activity or Fragment.
8 | */
9 | public interface MvpView {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/ui/main/MainMvpView.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.ui.main;
2 |
3 | import java.util.List;
4 |
5 | import be.neodigi.androidboilerplate.data.model.User;
6 | import be.neodigi.androidboilerplate.ui.base.MvpView;
7 |
8 | public interface MainMvpView extends MvpView {
9 |
10 | void showUsers(List users);
11 |
12 | void showUsersEmpty();
13 |
14 | void showError();
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/config/quality/findbugs/android-exclude-filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidBoilerPlate
3 |
4 | Settings
5 |
6 | OK
7 | Cancel
8 | Sorry
9 |
10 | There aren\'t any users
11 | There was a problem loading the users
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/scope/PerActivity.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.scope;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Scope;
7 |
8 | /**
9 | * A scoping annotation to permit objects whose lifetime should
10 | * conform to the life of the Activity to be memorised in the
11 | * correct component.
12 | */
13 | @Scope
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface PerActivity {
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 24sp
7 | 22sp
8 | 20sp
9 | 18sp
10 | 16sp
11 | 14sp
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/commonTest/java/be/neodigi/androidboilerplate/test/common/injection/component/TestComponent.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.test.common.injection.component;
2 |
3 | import javax.inject.Singleton;
4 |
5 | import be.neodigi.androidboilerplate.injection.component.ApplicationComponent;
6 | import be.neodigi.androidboilerplate.test.common.injection.module.ApplicationTestModule;
7 | import dagger.Component;
8 |
9 | @Singleton
10 | @Component(modules = ApplicationTestModule.class)
11 | public interface TestComponent extends ApplicationComponent {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/ConfigPersistent.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.inject.Scope;
7 |
8 | import be.neodigi.androidboilerplate.injection.component.ConfigPersistentComponent;
9 |
10 | /**
11 | * A scoping annotation to permit dependencies conform to the life of the
12 | * {@link ConfigPersistentComponent}
13 | */
14 | @Scope
15 | @Retention(RetentionPolicy.RUNTIME)
16 | public @interface ConfigPersistent {
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/component/ActivityComponent.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.component;
2 |
3 | import be.neodigi.androidboilerplate.injection.scope.PerActivity;
4 | import be.neodigi.androidboilerplate.injection.module.ActivityModule;
5 | import be.neodigi.androidboilerplate.ui.main.MainActivity;
6 | import dagger.Subcomponent;
7 |
8 | /**
9 | * This component inject dependencies to all Activities across the application
10 | */
11 | @PerActivity
12 | @Subcomponent(modules = ActivityModule.class)
13 | public interface ActivityComponent {
14 |
15 | void inject(MainActivity mainActivity);
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/module/ActivityModule.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.module;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 |
6 | import be.neodigi.androidboilerplate.injection.ActivityContext;
7 | import dagger.Module;
8 | import dagger.Provides;
9 |
10 | @Module
11 | public class ActivityModule {
12 |
13 | private Activity mActivity;
14 |
15 | public ActivityModule(Activity activity) {
16 | mActivity = activity;
17 | }
18 |
19 | @Provides
20 | Activity provideActivity() {
21 | return mActivity;
22 | }
23 |
24 | @Provides
25 | @ActivityContext
26 | Context providesContext() {
27 | return mActivity;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/data/local/PreferencesHelper.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.data.local;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import javax.inject.Inject;
7 | import javax.inject.Singleton;
8 |
9 | import be.neodigi.androidboilerplate.injection.ApplicationContext;
10 |
11 | @Singleton
12 | public class PreferencesHelper {
13 |
14 | public static final String PREF_FILE_NAME = "android_boilerplate_pref_file";
15 |
16 | private final SharedPreferences mPref;
17 |
18 | @Inject
19 | public PreferencesHelper(@ApplicationContext Context context) {
20 | mPref = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
21 | }
22 |
23 | public void clear() {
24 | mPref.edit().clear().apply();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/component/ConfigPersistentComponent.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.component;
2 |
3 | import be.neodigi.androidboilerplate.injection.ConfigPersistent;
4 | import be.neodigi.androidboilerplate.injection.module.ActivityModule;
5 | import be.neodigi.androidboilerplate.ui.base.BaseActivity;
6 | import dagger.Component;
7 |
8 | /**
9 | * A dagger component that will live during the lifecycle of an Activity but it won't
10 | * be destroy during configuration changes. Check {@link BaseActivity} to see how this components
11 | * survives configuration changes.
12 | * Use the {@link ConfigPersistent} scope to annotate dependencies that need to survive
13 | * configuration changes (for example Presenters).
14 | */
15 | @ConfigPersistent
16 | @Component(dependencies = ApplicationComponent.class)
17 | public interface ConfigPersistentComponent {
18 |
19 | ActivityComponent activityComponent(ActivityModule activityModule);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/util/ViewUtil.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.view.inputmethod.InputMethodManager;
7 |
8 | public final class ViewUtil {
9 |
10 | public static float pxToDp(float px) {
11 | float densityDpi = Resources.getSystem().getDisplayMetrics().densityDpi;
12 | return px / (densityDpi / 160f);
13 | }
14 |
15 | public static int dpToPx(int dp) {
16 | float density = Resources.getSystem().getDisplayMetrics().density;
17 | return Math.round(dp * density);
18 | }
19 |
20 | public static void hideKeyboard(Activity activity) {
21 | InputMethodManager imm =
22 | (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
23 | imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/util/NetworkUtil.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | import retrofit2.adapter.rxjava.HttpException;
8 |
9 | public class NetworkUtil {
10 |
11 | /**
12 | * Returns true if the Throwable is an instance of RetrofitError with an
13 | * http status code equals to the given one.
14 | */
15 | public static boolean isHttpStatusCode(Throwable throwable, int statusCode) {
16 | return throwable instanceof HttpException
17 | && ((HttpException) throwable).code() == statusCode;
18 | }
19 |
20 | public static boolean isNetworkConnected(Context context) {
21 | ConnectivityManager cm =
22 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
23 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
24 | return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/app/src/commonTest/java/be/neodigi/androidboilerplate/test/common/TestDataFactory.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.test.common;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.UUID;
6 |
7 | import be.neodigi.androidboilerplate.data.model.User;
8 |
9 | /**
10 | * Factory class that makes instances of data models with random field values.
11 | * The aim of this class is to help setting up test fixtures.
12 | */
13 | public class TestDataFactory {
14 |
15 | public static String randomUuid() {
16 | return UUID.randomUUID().toString();
17 | }
18 |
19 | public static User makeUser(String uniqueSuffix) {
20 | User u = new User();
21 | u.setId(1);
22 | u.setName(uniqueSuffix);
23 | u.setEmail(uniqueSuffix);
24 | u.setUsername(uniqueSuffix);
25 | return u;
26 | }
27 |
28 | public static List makeListUsers(int number) {
29 | List users = new ArrayList<>();
30 | for (int i = 0; i < number; i++) {
31 | users.add(makeUser(String.valueOf(i)));
32 | }
33 | return users;
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/be/neodigi/androidboilerplate/runner/RxAndroidJUnitRunner.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.runner;
2 |
3 | import android.os.Bundle;
4 | import android.support.test.espresso.Espresso;
5 |
6 | import be.neodigi.androidboilerplate.util.RxIdlingExecutionHook;
7 | import be.neodigi.androidboilerplate.util.RxIdlingResource;
8 | import rx.plugins.RxJavaPlugins;
9 |
10 | /**
11 | * Runner that registers a Espresso Indling resource that handles waiting for
12 | * RxJava Observables to finish.
13 | * WARNING - Using this runner will block the tests if the application uses long-lived hot
14 | * Observables such us event buses, etc.
15 | */
16 | public class RxAndroidJUnitRunner extends UnlockDeviceAndroidJUnitRunner {
17 |
18 | @Override
19 | public void onCreate(Bundle arguments) {
20 | super.onCreate(arguments);
21 | RxIdlingResource rxIdlingResource = new RxIdlingResource();
22 | RxJavaPlugins.getInstance()
23 | .registerObservableExecutionHook(new RxIdlingExecutionHook(rxIdlingResource));
24 | Espresso.registerIdlingResources(rxIdlingResource);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/ui/base/BasePresenter.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.ui.base;
2 |
3 | /**
4 | * Base class that implements the Presenter interface and provides a base implementation for
5 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that
6 | * can be accessed from the children classes by calling getMvpView().
7 | */
8 | public class BasePresenter implements Presenter {
9 |
10 | private T mMvpView;
11 |
12 | @Override
13 | public void attachView(T mvpView) {
14 | mMvpView = mvpView;
15 | }
16 |
17 | @Override
18 | public void detachView() {
19 | mMvpView = null;
20 | }
21 |
22 | public boolean isViewAttached() {
23 | return mMvpView != null;
24 | }
25 |
26 | public T getMvpView() {
27 | return mMvpView;
28 | }
29 |
30 | public void checkViewAttached() {
31 | if (!isViewAttached()) throw new MvpViewNotAttachedException();
32 | }
33 |
34 | public static class MvpViewNotAttachedException extends RuntimeException {
35 | public MvpViewNotAttachedException() {
36 | super("Please call Presenter.attachView(MvpView) before" +
37 | " requesting data to the Presenter");
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/component/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.component;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import javax.inject.Singleton;
7 |
8 | import be.neodigi.androidboilerplate.data.DataManager;
9 | import be.neodigi.androidboilerplate.data.SyncService;
10 | import be.neodigi.androidboilerplate.data.local.DatabaseHelper;
11 | import be.neodigi.androidboilerplate.data.local.PreferencesHelper;
12 | import be.neodigi.androidboilerplate.data.remote.RestService;
13 | import be.neodigi.androidboilerplate.injection.ApplicationContext;
14 | import be.neodigi.androidboilerplate.injection.module.ApplicationModule;
15 | import be.neodigi.androidboilerplate.injection.module.RestModule;
16 | import be.neodigi.androidboilerplate.util.RxEventBus;
17 | import dagger.Component;
18 | import io.realm.Realm;
19 |
20 | @Singleton
21 | @Component(modules = {ApplicationModule.class, RestModule.class})
22 | public interface ApplicationComponent {
23 |
24 | void inject(SyncService syncService);
25 |
26 | @ApplicationContext Context context();
27 | Application application();
28 | RestService restService();
29 | PreferencesHelper preferencesHelper();
30 | DatabaseHelper databaseHelper();
31 | Realm realm();
32 | DataManager dataManager();
33 | RxEventBus eventBus();
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/util/AndroidComponentUtil.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.ActivityManager.RunningServiceInfo;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.content.pm.PackageManager;
8 |
9 | public final class AndroidComponentUtil {
10 |
11 | public static void toggleComponent(Context context, Class componentClass, boolean enable) {
12 | ComponentName componentName = new ComponentName(context, componentClass);
13 | PackageManager pm = context.getPackageManager();
14 | pm.setComponentEnabledSetting(componentName,
15 | enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
16 | PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
17 | PackageManager.DONT_KILL_APP);
18 | }
19 |
20 | public static boolean isServiceRunning(Context context, Class serviceClass) {
21 | ActivityManager manager =
22 | (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
23 | for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
24 | if (serviceClass.getName().equals(service.service.getClassName())) {
25 | return true;
26 | }
27 | }
28 | return false;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/be/neodigi/androidboilerplate/util/RxIdlingExecutionHook.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import rx.Observable;
4 | import rx.Subscription;
5 | import rx.plugins.RxJavaObservableExecutionHook;
6 |
7 | /**
8 | * RxJava Observable execution hook that handles updating the active subscription
9 | * count for a given Espresso RxIdlingResource.
10 | */
11 | public class RxIdlingExecutionHook extends RxJavaObservableExecutionHook {
12 |
13 | private RxIdlingResource mRxIdlingResource;
14 |
15 | public RxIdlingExecutionHook(RxIdlingResource rxIdlingResource) {
16 | mRxIdlingResource = rxIdlingResource;
17 | }
18 |
19 | @Override
20 | public Observable.OnSubscribe onSubscribeStart(
21 | Observable extends T> observableInstance, Observable.OnSubscribe onSubscribe) {
22 | mRxIdlingResource.incrementActiveSubscriptionsCount();
23 | return super.onSubscribeStart(observableInstance, onSubscribe);
24 | }
25 |
26 | @Override
27 | public Throwable onSubscribeError(Throwable e) {
28 | mRxIdlingResource.decrementActiveSubscriptionsCount();
29 | return super.onSubscribeError(e);
30 | }
31 |
32 | @Override
33 | public Subscription onSubscribeReturn(Subscription subscription) {
34 | mRxIdlingResource.decrementActiveSubscriptionsCount();
35 | return super.onSubscribeReturn(subscription);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/be/neodigi/androidboilerplate/injection/module/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.injection.module;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import javax.inject.Singleton;
7 |
8 | import be.neodigi.androidboilerplate.injection.ApplicationContext;
9 | import dagger.Module;
10 | import dagger.Provides;
11 | import io.realm.Realm;
12 | import io.realm.RealmConfiguration;
13 |
14 | /**
15 | * Provide application-level dependencies.
16 | */
17 | @Module
18 | public class ApplicationModule {
19 | private final Application mApplication;
20 |
21 | public ApplicationModule(Application application) {
22 | mApplication = application;
23 | }
24 |
25 | @Provides
26 | Application provideApplication() {
27 | return mApplication;
28 | }
29 |
30 | @Provides
31 | @ApplicationContext
32 | Context provideContext() {
33 | return mApplication;
34 | }
35 |
36 | @Provides
37 | @Singleton
38 | RealmConfiguration provideRealmConfiguration(@ApplicationContext Context context) {
39 | Realm.init(context);
40 | RealmConfiguration.Builder builder = new RealmConfiguration.Builder();
41 | builder.name("boilerplate.realm");
42 | return builder.build();
43 | }
44 |
45 | @Provides
46 | Realm provideRealm(RealmConfiguration realmConfiguration) {
47 | return Realm.getInstance(realmConfiguration);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/test/java/be/neodigi/androidboilerplate/util/RxEventBusTest.java:
--------------------------------------------------------------------------------
1 | package be.neodigi.androidboilerplate.util;
2 |
3 | import org.junit.Before;
4 | import org.junit.Rule;
5 | import org.junit.Test;
6 |
7 | import rx.observers.TestSubscriber;
8 |
9 | public class RxEventBusTest {
10 |
11 | private RxEventBus mEventBus;
12 |
13 | @Rule
14 | // Must be added to every test class that targets app code that uses RxJava
15 | public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule();
16 |
17 | @Before
18 | public void setUp() {
19 | mEventBus = new RxEventBus();
20 | }
21 |
22 | @Test
23 | public void postedObjectsAreReceived() {
24 | TestSubscriber