├── .gitignore
├── AndroidSandbox.iml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ ├── ApplicationModule.java
│ │ ├── MainActivity.java
│ │ ├── MainActivityComponent.java
│ │ ├── SandboxApplication.java
│ │ └── SandboxApplicationComponent.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ ├── activity_main.xml
│ └── content_main.xml
│ └── values
│ └── strings.xml
├── build.gradle
├── common
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── common
│ │ ├── Preconditions.java
│ │ └── TextUtils.java
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── common
│ └── TextUtilsTest.java
├── commonandroid
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── commonandroid
│ │ └── BundleImmutableConverterAndroidUtilsTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── commonandroid
│ │ ├── BundleImmutable.java
│ │ ├── BundleImmutableConverterAndroidUtils.java
│ │ ├── IBundle.java
│ │ └── IntentImmutable.java
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── commonandroid
│ ├── BundleImmutableTest.java
│ ├── ExampleUnitTest.java
│ └── IntentImmutableTest.java
├── commonlayout
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── res
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── ExampleUnitTest.java
├── commontest
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── commontest
│ │ └── TestSubscriberEx.java
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── commontest
│ └── TestSubscriberExTest.java
├── featuresecond
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── tomaszpolanski
│ │ │ └── androidsandbox
│ │ │ ├── ISecondFeatureAppComponent.java
│ │ │ ├── SecondActivity.java
│ │ │ ├── SecondActivityComponent.java
│ │ │ └── SecondActivityModule.java
│ └── res
│ │ ├── layout
│ │ ├── activity_secondary_feature.xml
│ │ └── content_secondary_feature.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── second
│ └── ExampleUnitTest.java
├── featurethird
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── tomaszpolanski
│ │ │ └── androidsandbox
│ │ │ ├── IThirdFeatureAppComponent.java
│ │ │ ├── ThirdActivity.java
│ │ │ ├── ThirdActivityComponent.java
│ │ │ └── ThirdActivityModule.java
│ └── res
│ │ ├── layout
│ │ ├── activity_third.xml
│ │ └── content_third.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── ExampleUnitTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── injection
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── injection
│ │ ├── Injector.java
│ │ ├── activity
│ │ ├── BaseActivity.java
│ │ ├── BaseActivityComponent.java
│ │ ├── BaseActivityModule.java
│ │ ├── ForActivity.java
│ │ └── PerActivity.java
│ │ └── app
│ │ ├── Application.java
│ │ ├── BaseApplication.java
│ │ ├── BaseApplicationComponent.java
│ │ ├── BaseApplicationModule.java
│ │ └── IApplication.java
│ └── res
│ └── values
│ └── strings.xml
├── java-test.gradle
├── providers
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── tomaszpolanski
│ │ └── androidsandbox
│ │ └── providers
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── tomaszpolanski
│ │ │ └── androidsandbox
│ │ │ └── providers
│ │ │ ├── INavigator.java
│ │ │ ├── IResourceProvider.java
│ │ │ ├── Navigator.java
│ │ │ └── ResourceProvider.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── tomaszpolanski
│ └── androidsandbox
│ └── providers
│ └── ExampleUnitTest.java
├── retrolambda.gradle
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Log Files
26 | *.log
27 | /.idea
28 | *.iml
29 | app/app.iml
30 |
--------------------------------------------------------------------------------
/AndroidSandbox.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR T
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Modularizing Android application - WIP
2 |
3 | In this branch I modularize layers of the application.
4 | The base layers are horizontal - that means that next module depends on the previous.
5 |
6 | The horizontal layers consists of:
7 | - utility classes
8 | - common services
9 | - styles
10 |
11 | The vertical layers are the features.
12 | In this app they are only devided by basic activities, but in real app they could be features like:
13 | - home activity
14 | - settings activity and it's only dependencies
15 | - search activity
16 | - and many more
17 |
18 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 | apply plugin: 'me.tatarka.retrolambda'
4 |
5 | buildscript {
6 | repositories {
7 | jcenter()
8 | }
9 |
10 | dependencies {
11 | classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
12 | }
13 | configurations.classpath.exclude group: 'com.android.tools.external.lombok'
14 | }
15 |
16 | android {
17 | compileSdkVersion 23
18 | buildToolsVersion '24'
19 |
20 | compileOptions {
21 | sourceCompatibility JavaVersion.VERSION_1_8
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | }
24 |
25 | defaultConfig {
26 | applicationId "com.tomaszpolanski.androidsandbox"
27 | minSdkVersion 19
28 | targetSdkVersion 23
29 | versionCode 1
30 | versionName "0.1"
31 |
32 | }
33 | buildTypes {
34 | release {
35 | minifyEnabled false
36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
37 | }
38 | }
39 | lintOptions {
40 | disable 'InvalidPackage'
41 | }
42 | }
43 |
44 | repositories {
45 | jcenter()
46 | maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
47 | }
48 |
49 |
50 | dependencies {
51 | compile fileTree(dir: 'libs', include: ['*.jar'])
52 | compile project(':common')
53 | compile project(':providers')
54 | compile project(':commonlayout')
55 | compile project(':featuresecond')
56 | compile project(':featurethird')
57 | compile project(':injection')
58 |
59 | testCompile project(':commontest')
60 |
61 | compile 'com.android.support:appcompat-v7:23.4.0'
62 | compile 'com.android.support:design:23.4.0'
63 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha1'
64 |
65 | compile 'com.facebook.stetho:stetho:1.3.1'
66 | compile 'com.facebook.stetho:stetho-okhttp:1.3.1'
67 |
68 | // Dagger 2
69 | apt 'com.google.dagger:dagger-compiler:2.4'
70 | }
71 |
--------------------------------------------------------------------------------
/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 C:\Users\tomas_000\AppData\Local\Android\sdk/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/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tomaszpolanski/androidsandbox/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox;
2 |
3 | import com.tomaszpolanski.androidsandbox.injection.app.Application;
4 | import com.tomaszpolanski.androidsandbox.injection.app.BaseApplicationModule;
5 | import com.tomaszpolanski.androidsandbox.providers.INavigator;
6 | import com.tomaszpolanski.androidsandbox.providers.IResourceProvider;
7 | import com.tomaszpolanski.androidsandbox.providers.Navigator;
8 | import com.tomaszpolanski.androidsandbox.providers.ResourceProvider;
9 |
10 | import android.content.Context;
11 |
12 | import dagger.Module;
13 | import dagger.Provides;
14 |
15 | @Module(includes = {BaseApplicationModule.class})
16 | class ApplicationModule {
17 |
18 | @Provides
19 | IResourceProvider provideResourceProvider(@Application final Context context) {
20 | return new ResourceProvider(context);
21 | }
22 |
23 | @Provides
24 | INavigator provideNavigator(@Application final Context context) {
25 | return new Navigator(context);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tomaszpolanski/androidsandbox/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox;
2 |
3 | import com.tomaszpolanski.androidsandbox.injection.activity.BaseActivity;
4 | import com.tomaszpolanski.androidsandbox.injection.activity.BaseActivityModule;
5 | import com.tomaszpolanski.androidsandbox.providers.IResourceProvider;
6 |
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.support.annotation.NonNull;
10 | import android.support.annotation.Nullable;
11 | import android.support.design.widget.FloatingActionButton;
12 | import android.support.design.widget.Snackbar;
13 | import android.support.v7.widget.Toolbar;
14 |
15 | import javax.inject.Inject;
16 |
17 | import polanski.option.Option;
18 |
19 | import static com.tomaszpolanski.androidsandbox.common.Preconditions.get;
20 | import static polanski.option.Option.ofObj;
21 | import static polanski.option.OptionUnsafe.orThrowUnsafe;
22 |
23 | public class MainActivity extends BaseActivity {
24 |
25 | @Inject
26 | @Nullable
27 | IResourceProvider mResourceProvider;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_main);
33 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
34 | setSupportActionBar(toolbar);
35 | Option fab = Option.ofObj(findViewById(R.id.fab))
36 | .ofType(FloatingActionButton.class);
37 |
38 | fab.ifSome(button -> button.setOnClickListener(view -> Snackbar
39 | .make(view,
40 | get(mResourceProvider).getString(R.string.popup),
41 | Snackbar.LENGTH_LONG)
42 | .setAction("Start",
43 | __ -> startActivity(new Intent(this, ThirdActivity.class)))
44 | .show()));
45 | }
46 |
47 | @NonNull
48 | @Override
49 | protected MainActivityComponent createComponent() {
50 | return orThrowUnsafe(ofObj(getApplication())
51 | .ofType(SandboxApplication.class)
52 | .map(SandboxApplication::component)
53 | .map(it -> it.plusMainActivity(
54 | new BaseActivityModule(this))),
55 | new RuntimeException("Cannot inject " + getClass().getSimpleName()));
56 | }
57 |
58 | @Override
59 | public void inject() {
60 | component().inject(this);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tomaszpolanski/androidsandbox/MainActivityComponent.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox;
2 |
3 | import com.tomaszpolanski.androidsandbox.injection.activity.BaseActivityComponent;
4 | import com.tomaszpolanski.androidsandbox.injection.activity.BaseActivityModule;
5 | import com.tomaszpolanski.androidsandbox.injection.activity.PerActivity;
6 |
7 | import dagger.Subcomponent;
8 |
9 | @PerActivity
10 | @Subcomponent(modules = {BaseActivityModule.class})
11 | public interface MainActivityComponent extends BaseActivityComponent {
12 |
13 | void inject(final MainActivity activity);
14 | }
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tomaszpolanski/androidsandbox/SandboxApplication.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox;
2 |
3 | import com.facebook.stetho.Stetho;
4 | import com.tomaszpolanski.androidsandbox.injection.app.BaseApplication;
5 | import com.tomaszpolanski.androidsandbox.injection.app.BaseApplicationModule;
6 |
7 | import android.support.annotation.NonNull;
8 |
9 | public class SandboxApplication extends BaseApplication {
10 |
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | initStetho();
15 | }
16 |
17 | @Override
18 | public void inject() {
19 | component().inject(this);
20 | }
21 |
22 | @NonNull
23 | protected SandboxApplicationComponent createComponent() {
24 | return DaggerSandboxApplicationComponent.builder()
25 | .baseApplicationModule(
26 | new BaseApplicationModule(this))
27 | .build();
28 | }
29 |
30 | private void initStetho() {
31 | Stetho.initialize(
32 | Stetho.newInitializerBuilder(this)
33 | .enableDumpapp(Stetho.defaultDumperPluginsProvider(this))
34 | .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this))
35 | .build());
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tomaszpolanski/androidsandbox/SandboxApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox;
2 |
3 | import com.tomaszpolanski.androidsandbox.injection.activity.BaseActivityModule;
4 | import com.tomaszpolanski.androidsandbox.injection.app.Application;
5 |
6 | import android.content.Context;
7 |
8 | import javax.inject.Singleton;
9 |
10 | import dagger.Component;
11 |
12 | @Singleton
13 | @Component(modules = ApplicationModule.class)
14 | public interface SandboxApplicationComponent extends ISecondFeatureAppComponent,
15 | IThirdFeatureAppComponent{
16 |
17 | android.app.Application getApplication();
18 |
19 | @Application
20 | Context getApplicationContext();
21 |
22 | MainActivityComponent plusMainActivity(BaseActivityModule splashActivityModule);
23 |
24 | void inject(final SandboxApplication application);
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomaszpolanski/Android-Modularization/17e2e4ad69ac2a950be3acff272a610d37e35536/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomaszpolanski/Android-Modularization/17e2e4ad69ac2a950be3acff272a610d37e35536/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomaszpolanski/Android-Modularization/17e2e4ad69ac2a950be3acff272a610d37e35536/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomaszpolanski/Android-Modularization/17e2e4ad69ac2a950be3acff272a610d37e35536/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/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_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AndroidSandbox
5 | Hello world!
6 | Settings
7 | Main
8 | SecondaryFeatureActivity
9 | ThirdActivity
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | def getLocalRepository() {
2 | String androidHome = System.getenv().get("ANDROID_HOME")
3 | if (androidHome == null) {
4 | throw new StopActionException("System env does not contain ANDROID_HOME. " +
5 | "Set it to point to your Android SDK.")
6 | }
7 | return androidHome + "/extras/android/m2repository"
8 | }
9 |
10 | allprojects {
11 | repositories {
12 | mavenLocal()
13 | mavenCentral()
14 | jcenter()
15 | maven { url getLocalRepository() }
16 | maven { url "https://jitpack.io" }
17 | }
18 | buildscript {
19 | dependencies {
20 | classpath 'com.android.tools.build:gradle:2.1.2'
21 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' // needed for AutoValue
22 | classpath 'me.tatarka:gradle-retrolambda:3.2.5'
23 | }
24 | repositories {
25 | mavenLocal()
26 | mavenCentral()
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/common/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply from: '../retrolambda.gradle'
3 | apply from: '../java-test.gradle'
4 |
5 | dependencies {
6 | compile 'com.android.support:support-annotations:23.3.0'
7 | compile 'io.reactivex:rxjava:1.1.0'
8 | compile 'com.github.tomaszpolanski:options:1.2.0'
9 |
10 | retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:2.3.0'
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/tomaszpolanski/androidsandbox/common/Preconditions.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox.common;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.annotation.Nullable;
5 |
6 | public final class Preconditions {
7 |
8 | @NonNull
9 | public static T get(@Nullable final T value) {
10 | if (value == null) {
11 | throw new NullPointerException("Value cannot be null.");
12 | }
13 | return value;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/common/src/main/java/com/tomaszpolanski/androidsandbox/common/TextUtils.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox.common;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.annotation.Nullable;
5 |
6 | /**
7 | * Provides similar behaviour to Android's class but is able to be unit testable.
8 | * Android's implementation is a stub.
9 | */
10 | public final class TextUtils {
11 |
12 | private TextUtils() {
13 | }
14 |
15 | /**
16 | * Returns true if the string is null or 0-length.
17 | *
18 | * @param string the string to be examined
19 | * @return true if string is null or zero length
20 | */
21 | public static boolean isEmpty(@Nullable CharSequence string) {
22 | return string == null || string.length() == 0;
23 | }
24 |
25 | /**
26 | * Returns false if the string is null or 0-length.
27 | *
28 | * @param string the string to be examined
29 | * @return false if string is null or zero length
30 | */
31 | public static boolean isNotEmpty(@Nullable CharSequence string) {
32 | return !isEmpty(string);
33 | }
34 |
35 | /**
36 | * Returns a string containing the tokens joined by delimiters.
37 | * This is a copy of Android TextUtils implementation
38 | *
39 | * @param tokens an array objects to be joined. Strings will be formed from
40 | * the objects by calling object.toString().
41 | * @see TextUtils
42 | */
43 | @NonNull
44 | public static String join(@NonNull final CharSequence delimiter,
45 | @NonNull final Iterable tokens) {
46 | StringBuilder sb = new StringBuilder();
47 | boolean firstTime = true;
48 | for (Object token : tokens) {
49 | if (firstTime) {
50 | firstTime = false;
51 | } else {
52 | sb.append(delimiter);
53 | }
54 | sb.append(token);
55 | }
56 | return sb.toString();
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/common/src/test/java/com/tomaszpolanski/androidsandbox/common/TextUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox.common;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.assertj.core.api.Assertions.assertThat;
6 |
7 | public class TextUtilsTest {
8 |
9 | @Test
10 | public void isEmpty_WhenStringIsNull() {
11 | assertThat(TextUtils.isEmpty(null)).isTrue();
12 | }
13 |
14 | @Test
15 | public void isEmpty_WhenStringIsEmpty() {
16 | assertThat(TextUtils.isEmpty("")).isTrue();
17 | }
18 |
19 | @Test
20 | public void isEmpty_WhenStringIsNotEmpty() {
21 | assertThat(TextUtils.isEmpty("not empty")).isFalse();
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/commonandroid/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/commonandroid/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.neenbedankt.android-apt' // needed for AutoValue
3 | apply from: '../java-test.gradle'
4 | apply from: '../retrolambda.gradle'
5 |
6 |
7 | android {
8 | compileSdkVersion 23
9 | buildToolsVersion '24'
10 |
11 | compileOptions {
12 | sourceCompatibility JavaVersion.VERSION_1_8
13 | targetCompatibility JavaVersion.VERSION_1_8
14 | }
15 |
16 | defaultConfig {
17 | minSdkVersion 19
18 | targetSdkVersion 23
19 | versionCode 1
20 | versionName "1.0"
21 |
22 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
23 | }
24 | // Fixes issue: com.android.build.api.transform.TransformException:
25 | // com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK asm-license.txt
26 | packagingOptions {
27 | exclude 'asm-license.txt'
28 | }
29 |
30 | buildTypes {
31 | release {
32 | minifyEnabled false
33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34 | }
35 | }
36 | }
37 |
38 | dependencies {
39 | compile project(':common')
40 | testCompile project(path: ':commontest')
41 |
42 | provided 'com.google.auto.value:auto-value:1.2'
43 | apt 'com.google.auto.value:auto-value:1.2'
44 |
45 | androidTestCompile 'com.google.dexmaker:dexmaker:1.2' // to fix ExceptionInInitializerError issue in mockito
46 | androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
47 |
48 | androidTestCompile 'com.android.support.test:runner:0.3'
49 | androidTestCompile 'org.mockito:mockito-core:2.0.7-beta'
50 | androidTestCompile 'org.assertj:assertj-core:1.7.1'
51 | androidTestCompile 'junit:junit:4.12'
52 | }
53 |
--------------------------------------------------------------------------------
/commonandroid/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 C:\Users\Kriger\AppData\Local\Android\sdk/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 |
--------------------------------------------------------------------------------
/commonandroid/src/androidTest/java/com/tomaszpolanski/androidsandbox/commonandroid/BundleImmutableConverterAndroidUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox.commonandroid;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 |
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.Parcelable;
9 | import android.support.test.runner.AndroidJUnit4;
10 |
11 | import java.io.Serializable;
12 |
13 | import polanski.option.Option;
14 |
15 | import static com.tomaszpolanski.androidsandbox.commonandroid.BundleImmutable.Builder.builder;
16 | import static com.tomaszpolanski.androidsandbox.commonandroid.BundleImmutableConverterAndroidUtils.from;
17 | import static org.assertj.core.api.Assertions.assertThat;
18 | import static org.mockito.Mockito.mock;
19 | import static polanski.option.OptionUnsafe.getUnsafe;
20 |
21 | @RunWith(AndroidJUnit4.class)
22 | public class BundleImmutableConverterAndroidUtilsTest {
23 |
24 | private static final String KEY = "Key";
25 |
26 | @Test
27 | public void testFrom_deserializeString() {
28 | String value = "SomeString";
29 | Bundle bundle = new Bundle();
30 | bundle.putString(KEY, value);
31 |
32 | Option bundleIm = from(bundle);
33 |
34 | assertThat(getUnsafe(bundleIm).getString(KEY))
35 | .isEqualTo(Option.ofObj(value));
36 | }
37 |
38 | @Test
39 | public void testFrom_deserializeInt() {
40 | int value = 21;
41 | Bundle bundle = new Bundle();
42 | bundle.putInt(KEY, value);
43 |
44 | Option bundleIm = from(bundle);
45 |
46 | assertThat(getUnsafe(bundleIm).getInt(KEY))
47 | .isEqualTo(Option.ofObj(value));
48 | }
49 |
50 | @Test
51 | public void testFrom_deserializeFloat() {
52 | float value = 21.1f;
53 | Bundle bundle = new Bundle();
54 | bundle.putFloat(KEY, value);
55 |
56 | Option bundleIm = from(bundle);
57 |
58 | assertThat(getUnsafe(bundleIm).getFloat(KEY))
59 | .isEqualTo(Option.ofObj(value));
60 | }
61 |
62 | @SuppressWarnings("ConstantConditions")
63 | @Test
64 | public void testFrom_deserializeBoolean() {
65 | boolean value = false;
66 | Bundle bundle = new Bundle();
67 | bundle.putBoolean(KEY, value);
68 |
69 | Option bundleIm = from(bundle);
70 |
71 | assertThat(getUnsafe(bundleIm).getBoolean(KEY))
72 | .isEqualTo(Option.ofObj(value));
73 | }
74 |
75 | @Test
76 | public void testFrom_deserializeObject() {
77 | IBinder value = mock(IBinder.class);
78 | Bundle bundle = new Bundle();
79 | bundle.putBinder(KEY, value);
80 |
81 | Option bundleIm = from(bundle);
82 |
83 | assertThat(getUnsafe(bundleIm).getObject(KEY))
84 | .isEqualTo(Option.ofObj(value));
85 | }
86 |
87 | @Test
88 | public void testFrom_serializeString() {
89 | String value = "SomeString";
90 | BundleImmutable bundleIm = builder().put(KEY, value)
91 | .build();
92 |
93 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
94 |
95 | assertThat(getUnsafe(bundle).getString(KEY))
96 | .isEqualTo(value);
97 | }
98 |
99 | @Test
100 | public void testFrom_serializeInt() {
101 | int value = 43;
102 | BundleImmutable bundleIm = builder().put(KEY, value)
103 | .build();
104 |
105 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
106 |
107 | assertThat(getUnsafe(bundle).getInt(KEY))
108 | .isEqualTo(value);
109 | }
110 |
111 | @Test
112 | public void testFrom_serializeFloat() {
113 | float value = 43.4f;
114 | BundleImmutable bundleIm = builder().put(KEY, value)
115 | .build();
116 |
117 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
118 |
119 | assertThat(getUnsafe(bundle).getFloat(KEY))
120 | .isEqualTo(value);
121 | }
122 |
123 | @SuppressWarnings("ConstantConditions")
124 | @Test
125 | public void testFrom_serializeBoolean() {
126 | boolean value = false;
127 | BundleImmutable bundleIm = builder().put(KEY, value)
128 | .build();
129 |
130 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
131 |
132 | assertThat(getUnsafe(bundle).getBoolean(KEY))
133 | .isEqualTo(value);
134 | }
135 |
136 | @Test
137 | public void testFrom_serializeParcelable() {
138 | Parcelable value = mock(Parcelable.class);
139 | BundleImmutable bundleIm = builder().put(KEY, value)
140 | .build();
141 |
142 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
143 |
144 | Parcelable result = getUnsafe(bundle).getParcelable(KEY);
145 | assertThat(result).isEqualTo(value);
146 | }
147 |
148 | @Test
149 | public void testFrom_serializeSerializable() {
150 | Serializable value = mock(Serializable.class);
151 | BundleImmutable bundleIm = builder().put(KEY, value)
152 | .build();
153 |
154 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
155 |
156 | assertThat(getUnsafe(bundle).getSerializable(KEY))
157 | .isEqualTo(value);
158 | }
159 |
160 | @Test
161 | public void testFrom_serializeUnknownObject() {
162 | Object value = mock(Object.class);
163 | BundleImmutable bundleIm = builder().put(KEY, value)
164 | .build();
165 |
166 | Option bundle = BundleImmutableConverterAndroidUtils.to(bundleIm);
167 |
168 | assertThat(bundle).isEqualTo(Option.none());
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/commonandroid/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/commonandroid/src/main/java/com/tomaszpolanski/androidsandbox/commonandroid/BundleImmutable.java:
--------------------------------------------------------------------------------
1 | package com.tomaszpolanski.androidsandbox.commonandroid;
2 |
3 | import android.os.Parcelable;
4 | import android.support.annotation.NonNull;
5 |
6 | import java.io.Serializable;
7 | import java.util.Collections;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | import polanski.option.Option;
12 |
13 | public class BundleImmutable implements IBundle {
14 |
15 | @NonNull
16 | public static final BundleImmutable EMPTY = new Builder().build();
17 |
18 | @NonNull
19 | private final Map mMap;
20 |
21 | public BundleImmutable() {
22 | this(Collections.emptyMap());
23 | }
24 |
25 | public BundleImmutable(@NonNull final Map map) {
26 | mMap = new HashMap<>(map);
27 | }
28 |
29 | @NonNull
30 | @Override
31 | public Option getInt(@NonNull final String key) {
32 | return getObject(key)
33 | .ofType(Integer.class);
34 | }
35 |
36 | @NonNull
37 | @Override
38 | public Option getFloat(@NonNull final String key) {
39 | return getObject(key)
40 | .ofType(Float.class);
41 | }
42 |
43 | @NonNull
44 | @Override
45 | public Option getBoolean(@NonNull final String key) {
46 | return getObject(key)
47 | .ofType(Boolean.class);
48 | }
49 |
50 | @NonNull
51 | @Override
52 | public Option getString(@NonNull final String key) {
53 | return getObject(key)
54 | .ofType(String.class);
55 | }
56 |
57 | @NonNull
58 | @Override
59 | public Option getParcelable(@NonNull final String key) {
60 | return getObject(key)
61 | .ofType(Parcelable.class);
62 | }
63 |
64 | @NonNull
65 | @Override
66 | public Option getSerializable(@NonNull final String key) {
67 | return getObject(key)
68 | .ofType(Serializable.class);
69 | }
70 |
71 | @NonNull
72 | @Override
73 | public Option