├── app ├── .gitignore ├── .settings │ └── org.eclipse.buildship.core.prefs ├── src │ ├── local │ │ └── res │ │ │ └── raw │ │ │ └── app_config.json │ ├── main │ │ ├── ic_launcher-web.png │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── ag_avatar.png │ │ │ │ ├── ic_lock.png │ │ │ │ ├── baseline_warning.png │ │ │ │ ├── ic_openid_connect.png │ │ │ │ ├── baseline_verified_user.png │ │ │ │ ├── authentication_background.png │ │ │ │ ├── menu_color.xml │ │ │ │ ├── ic_home.xml │ │ │ │ ├── ic_clear.xml │ │ │ │ ├── menu_nav_bar.xml │ │ │ │ ├── ic_delete.xml │ │ │ │ ├── ic_person.xml │ │ │ │ ├── ic_config.xml │ │ │ │ ├── ic_storage.xml │ │ │ │ ├── background_gradient.xml │ │ │ │ ├── ic_device_os.xml │ │ │ │ ├── ic_security.xml │ │ │ │ ├── ic_message.xml │ │ │ │ ├── ic_insert_chart.xml │ │ │ │ ├── ic_note_add.xml │ │ │ │ ├── ic_refresh.xml │ │ │ │ ├── ic_crypto.xml │ │ │ │ ├── ic_memory.xml │ │ │ │ ├── profile_image_border.xml │ │ │ │ ├── ic_account_circle.xml │ │ │ │ ├── ic_http.xml │ │ │ │ ├── ic_lock_open.xml │ │ │ │ ├── ic_hooking.xml │ │ │ │ ├── ic_network_locked.xml │ │ │ │ ├── ic_phone_lock.xml │ │ │ │ ├── ic_notifications_active.xml │ │ │ │ ├── fh_icon.xml │ │ │ │ └── ic_error_background.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── layout │ │ │ │ ├── view_progress.xml │ │ │ │ ├── fragment_not_available_dialog.xml │ │ │ │ ├── item_http.xml │ │ │ │ ├── fragment_warning_title.xml │ │ │ │ ├── fragment_not_available_title.xml │ │ │ │ ├── push_registration_failed_title.xml │ │ │ │ ├── fragment_push.xml │ │ │ │ ├── menu_app_bar.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── fragment_notes_list.xml │ │ │ │ ├── content_area.xml │ │ │ │ ├── item_landing.xml │ │ │ │ ├── fragment_note.xml │ │ │ │ ├── fragment_home.xml │ │ │ │ ├── menu_nav_header.xml │ │ │ │ ├── item_push.xml │ │ │ │ ├── fragment_authentication.xml │ │ │ │ ├── fragment_landing_security.xml │ │ │ │ ├── fragment_under_construction.xml │ │ │ │ ├── fragment_network.xml │ │ │ │ └── fragment_landing.xml │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ └── menu │ │ │ │ └── menu_sidebar_content.xml │ │ ├── assets │ │ │ └── mobile-services.json │ │ ├── java │ │ │ └── com │ │ │ │ └── aerogear │ │ │ │ └── androidshowcase │ │ │ │ ├── navigation │ │ │ │ ├── GotoDocsListener.java │ │ │ │ ├── PushRegistrationFailedDialogFragment.java │ │ │ │ └── NotAvailableDialogFragment.java │ │ │ │ ├── features │ │ │ │ ├── push │ │ │ │ │ ├── views │ │ │ │ │ │ ├── PushView.java │ │ │ │ │ │ └── PushViewImpl.java │ │ │ │ │ ├── presenters │ │ │ │ │ │ └── PushPresenter.java │ │ │ │ │ ├── PushGestureViewHolder.java │ │ │ │ │ └── PushGestureAdapter.java │ │ │ │ ├── landing │ │ │ │ │ ├── views │ │ │ │ │ │ ├── LandingView.java │ │ │ │ │ │ └── LandingViewImpl.java │ │ │ │ │ ├── presenters │ │ │ │ │ │ └── LandingPresenter.java │ │ │ │ │ └── LandingFragment.java │ │ │ │ ├── documentation │ │ │ │ │ ├── views │ │ │ │ │ │ ├── DocumentationView.java │ │ │ │ │ │ └── DocumentationViewImpl.java │ │ │ │ │ ├── presenters │ │ │ │ │ │ └── DocumentationPresenter.java │ │ │ │ │ ├── DocumentUrl.java │ │ │ │ │ └── DocumentationFragment.java │ │ │ │ ├── underconstruction │ │ │ │ │ ├── views │ │ │ │ │ │ ├── UnderConstructionView.java │ │ │ │ │ │ └── UnderConstructionViewImpl.java │ │ │ │ │ ├── presenters │ │ │ │ │ │ └── UnderConstructionPresenter.java │ │ │ │ │ └── UnderConstructionFragment.java │ │ │ │ ├── home │ │ │ │ │ ├── views │ │ │ │ │ │ ├── HomeView.java │ │ │ │ │ │ └── HomeViewImpl.java │ │ │ │ │ ├── presenters │ │ │ │ │ │ └── HomeViewPresenter.java │ │ │ │ │ └── HomeFragment.java │ │ │ │ ├── device │ │ │ │ │ ├── views │ │ │ │ │ │ ├── DeviceView.java │ │ │ │ │ │ ├── DeviceViewImpl.java │ │ │ │ │ │ └── WarningDialog.java │ │ │ │ │ └── presenters │ │ │ │ │ │ └── DevicePresenter.java │ │ │ │ └── authentication │ │ │ │ │ ├── views │ │ │ │ │ ├── AuthenticationView.java │ │ │ │ │ ├── AuthenticationDetailsView.java │ │ │ │ │ ├── AuthenticationViewImpl.java │ │ │ │ │ └── AuthenticationDetailsViewImpl.java │ │ │ │ │ ├── providers │ │ │ │ │ ├── OpenIDAuthenticationProvider.java │ │ │ │ │ └── KeycloakAuthenticateProviderImpl.java │ │ │ │ │ └── presenters │ │ │ │ │ ├── AuthenticationDetailsPresenter.java │ │ │ │ │ └── AuthenticationViewPresenter.java │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── domain │ │ │ │ ├── callbacks │ │ │ │ │ └── CallbackHandler.java │ │ │ │ ├── configurations │ │ │ │ │ ├── ApiServerConfiguration.java │ │ │ │ │ └── AppConfiguration.java │ │ │ │ ├── models │ │ │ │ │ └── User.java │ │ │ │ ├── utils │ │ │ │ │ └── StreamUtils.java │ │ │ │ ├── crypto │ │ │ │ │ ├── SecureKeyStoreImpl.java │ │ │ │ │ ├── RsaCrypto.java │ │ │ │ │ ├── NullAndroidSecureKeyStore.java │ │ │ │ │ ├── RsaHelper.java │ │ │ │ │ ├── SecureKeyStore.java │ │ │ │ │ └── AndroidMSecureKeyStore.java │ │ │ │ └── Constants.java │ │ │ │ ├── di │ │ │ │ ├── MainActivityModule.java │ │ │ │ ├── SecureApplicationComponent.java │ │ │ │ ├── FragmentModules.java │ │ │ │ └── SecureApplicationModule.java │ │ │ │ ├── mvp │ │ │ │ ├── presenters │ │ │ │ │ ├── BasePresenter.java │ │ │ │ │ └── Presenter.java │ │ │ │ ├── views │ │ │ │ │ ├── AppView.java │ │ │ │ │ ├── BaseFragment.java │ │ │ │ │ └── BaseAppView.java │ │ │ │ └── components │ │ │ │ │ ├── ProgressDialogHelper.java │ │ │ │ │ ├── HttpHelper.java │ │ │ │ │ └── CertPinningHelper.java │ │ │ │ ├── SecureApplication.java │ │ │ │ ├── providers │ │ │ │ └── PushServiceProvider.java │ │ │ │ ├── CertificateErrorDialog.java │ │ │ │ └── handler │ │ │ │ └── NotificationBarMessageHandler.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── aerogear │ │ │ └── androidshowcase │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── aerogear │ │ └── androidshowcase │ │ ├── di │ │ ├── SecureTestApplication.java │ │ ├── SecureApplicationTestComponent.java │ │ └── SecureApplicationTestModule.java │ │ ├── MockTestRunner.java │ │ ├── RsaCryptoTest.java │ │ ├── domain │ │ └── store │ │ │ ├── sqlite │ │ │ └── SqliteNoteStoreTest.java │ │ │ ├── SecureFileNoteStoreTest.java │ │ │ └── NoteStoreTestBase.java │ │ ├── MainActivityInstrumentedTest.java │ │ └── AesCryptoTest.java ├── .classpath ├── .project ├── proguard-rules.pro └── google-services.json ├── settings.gradle ├── .settings └── org.eclipse.buildship.core.prefs ├── signing_keys.keystore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CODE_OF_CONDUCT └── CONTRIBUTING.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── pushToKryptowire.sh ├── .project ├── gradle.properties ├── .circleci └── config.yml ├── Jenkinsfile ├── gradlew.bat ├── readme.adoc └── CONTRIBUTING.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | #Tue Sep 05 10:43:45 IST 2017 2 | connection.project.dir= 3 | -------------------------------------------------------------------------------- /app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | #Tue Sep 05 10:43:45 IST 2017 2 | connection.project.dir=.. 3 | -------------------------------------------------------------------------------- /signing_keys.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/signing_keys.keystore -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | ## Default owners (going to be removed at later stage) 2 | * @danielpassos @secondsun @wei-lee 3 | -------------------------------------------------------------------------------- /app/src/local/res/raw/app_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "api-server": { 3 | "server-url": "http://www.rhdev.me:8080" 4 | } 5 | } -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/ag_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/ag_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/ic_lock.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .vscode 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/baseline_warning.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_openid_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/ic_openid_connect.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_verified_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/baseline_verified_user.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/authentication_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aerogear/android-showcase-template/HEAD/app/src/main/res/drawable/authentication_background.png -------------------------------------------------------------------------------- /app/src/main/assets/mobile-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "clusterName": "https://192.168.42.208:8443", 4 | "namespace": "showcase", 5 | "clientId": "myapp-android", 6 | "services": [ 7 | ] 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/navigation/GotoDocsListener.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.navigation; 2 | 3 | @FunctionalInterface 4 | interface GotoDocsListener { 5 | void goToDocs(); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/push/views/PushView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.push.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | public interface PushView extends AppView { 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/landing/views/LandingView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.landing.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | public interface LandingView extends AppView { 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 27 19:23:52 EDT 2018 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-4.6-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/documentation/views/DocumentationView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.documentation.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | public interface DocumentationView extends AppView { 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | 5 | /** 6 | * Created by weili on 12/09/2017. 7 | */ 8 | 9 | public class BaseActivity extends AppCompatActivity { 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_progress.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/underconstruction/views/UnderConstructionView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.underconstruction.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | public interface UnderConstructionView extends AppView { 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/home/views/HomeView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.home.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | /** 6 | * Created by weili on 12/09/2017. 7 | */ 8 | 9 | public interface HomeView extends AppView { 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/device/views/DeviceView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.device.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | 5 | /** 6 | * Created by tjackman on 16/10/17. 7 | */ 8 | 9 | public interface DeviceView extends AppView { 10 | } 11 | -------------------------------------------------------------------------------- /app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /pushToKryptowire.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 1 ]; then 4 | echo "Usage: $0 API_KEY" >&2 5 | exit 1 6 | fi 7 | 8 | KRYPTOWIRE_API_KEY=$1 9 | URL="https://appsrv2.kryptowire.com/api/analyze" 10 | PLATFORM="android" 11 | FILEPATH="./app/build/outputs/apk/app-release.apk" 12 | 13 | curl -X POST $URL -F file=@$FILEPATH -F key=$KRYPTOWIRE_API_KEY -F platform=$PLATFORM 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/landing/views/LandingViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.landing.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | public abstract class LandingViewImpl extends BaseAppView implements LandingView { 8 | public LandingViewImpl(Fragment fragment) { 9 | super(fragment); 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/callbacks/CallbackHandler.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.callbacks; 2 | 3 | /** 4 | * Represents the callback functions to be invoken when async functions are finished. 5 | */ 6 | 7 | public interface CallbackHandler { 8 | default void onSuccess() {} 9 | default void onSuccess(T models) {onSuccess();} 10 | void onError(Throwable error); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_config.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_storage.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/documentation/views/DocumentationViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.documentation.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | public class DocumentationViewImpl extends BaseAppView implements DocumentationView { 8 | public DocumentationViewImpl (Fragment fragment) { 9 | super(fragment); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/push/views/PushViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.push.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | /** 8 | * Created by tjackman on 02/05/18. 9 | */ 10 | 11 | public abstract class PushViewImpl extends BaseAppView implements PushView { 12 | public PushViewImpl(Fragment fragment) { 13 | super(fragment); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_device_os.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Add a brief and meaningful description. 3 | 4 | ## Expected Behavior 5 | Describe the expected behaviour. 6 | 7 | ## Actual Behavior 8 | Describe the current/actual behaviour. 9 | 10 | ## Environment 11 | - Core Version: 12 | - Auth Version: 13 | - Push Version: 14 | 15 | ## Steps to reproduce 16 | Describe all steps and pre-requirements which are required to be performed in order to reproduce this scenario. ( E.g 1. Action, 2. Action ... ) 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/device/views/DeviceViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.device.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | /** 8 | * Created by tjackman on 16/10/17. 9 | */ 10 | 11 | public class DeviceViewImpl extends BaseAppView implements DeviceView { 12 | public DeviceViewImpl(Fragment fragment) { 13 | super(fragment); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/home/views/HomeViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.home.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | /** 8 | * Created by weili on 12/09/2017. 9 | */ 10 | 11 | public abstract class HomeViewImpl extends BaseAppView implements HomeView { 12 | public HomeViewImpl(Fragment fragment) { 13 | super(fragment); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/landing/presenters/LandingPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.landing.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.push.views.PushView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | public class LandingPresenter extends BasePresenter { 9 | 10 | @Inject 11 | public LandingPresenter() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/underconstruction/views/UnderConstructionViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.underconstruction.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | public abstract class UnderConstructionViewImpl extends BaseAppView implements UnderConstructionView { 8 | public UnderConstructionViewImpl(Fragment fragment) { 9 | super(fragment); 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_security.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_message.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_insert_chart.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_note_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/documentation/presenters/DocumentationPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.documentation.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.documentation.views.DocumentationView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | public class DocumentationPresenter extends BasePresenter { 9 | @Inject 10 | public DocumentationPresenter() { 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/test/java/com/aerogear/androidshowcase/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/views/AuthenticationView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.views; 2 | import com.aerogear.androidshowcase.mvp.views.AppView; 3 | import org.aerogear.mobile.auth.user.UserPrincipal; 4 | 5 | 6 | /** 7 | * Created by weili on 12/09/2017. 8 | */ 9 | 10 | public interface AuthenticationView extends AppView { 11 | 12 | public void renderIdentityInfo(UserPrincipal user); 13 | 14 | public void showAuthError(Exception error); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/home/presenters/HomeViewPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.home.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.home.views.HomeView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | /** 9 | * Created by weili on 12/09/2017. 10 | */ 11 | 12 | public class HomeViewPresenter extends BasePresenter { 13 | @Inject 14 | public HomeViewPresenter() { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/views/AuthenticationDetailsView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.views; 2 | 3 | import com.aerogear.androidshowcase.mvp.views.AppView; 4 | import org.aerogear.mobile.auth.user.UserPrincipal; 5 | 6 | /** 7 | * Created by weili on 12/09/2017. 8 | */ 9 | 10 | public interface AuthenticationDetailsView extends AppView { 11 | 12 | public void logoutSuccess(UserPrincipal user); 13 | 14 | public void logoutFailure(Exception error); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/views/AuthenticationViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | /** 8 | * Created by weili on 12/09/2017. 9 | */ 10 | 11 | public abstract class AuthenticationViewImpl extends BaseAppView implements AuthenticationView { 12 | public AuthenticationViewImpl(Fragment fragment) { 13 | super(fragment); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/push/presenters/PushPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.push.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.push.views.PushView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | /** 9 | * Created by tjackman on 02/05/18. 10 | */ 11 | 12 | public class PushPresenter extends BasePresenter { 13 | 14 | @Inject 15 | public PushPresenter() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/underconstruction/presenters/UnderConstructionPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.underconstruction.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.push.views.PushView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | public class UnderConstructionPresenter extends BasePresenter { 9 | 10 | @Inject 11 | public UnderConstructionPresenter() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | AeroGear Android Showcase 4 | Project mobile-security-android-template created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/device/presenters/DevicePresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.device.presenters; 2 | 3 | import com.aerogear.androidshowcase.features.device.views.DeviceView; 4 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 5 | 6 | import javax.inject.Inject; 7 | 8 | /** 9 | * Created by tjackman on 16/10/17. 10 | */ 11 | 12 | public class DevicePresenter extends BasePresenter { 13 | 14 | @Inject 15 | public DevicePresenter() { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/di/MainActivityModule.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.di; 2 | 3 | import com.aerogear.androidshowcase.MainActivity; 4 | import dagger.Module; 5 | import dagger.android.ContributesAndroidInjector; 6 | 7 | /** 8 | * Define dependencies for the MainActivity. Used by Dagger2 to build dependency graph. 9 | */ 10 | @Module 11 | public abstract class MainActivityModule { 12 | 13 | @ContributesAndroidInjector(modules = {FragmentModules.class}) 14 | abstract MainActivity contributeMainActivityInjector(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/views/AuthenticationDetailsViewImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.views; 2 | 3 | import android.app.Fragment; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.BaseAppView; 6 | 7 | /** 8 | * Created by weili on 12/09/2017. 9 | */ 10 | 11 | public abstract class AuthenticationDetailsViewImpl extends BaseAppView implements AuthenticationDetailsView { 12 | public AuthenticationDetailsViewImpl(Fragment fragment) { 13 | super(fragment); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_crypto.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_memory.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/profile_image_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_http.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_not_available_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2e6980 4 | #4296b4 5 | #23242d 6 | #2e6980 7 | #000000 8 | #D82B32 9 | #008000 10 | #e25027 11 | #fff 12 | #8e8e8e 13 | #f4f4f4 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock_open.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/configurations/ApiServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.configurations; 2 | 3 | /** 4 | * Created by weili on 31/10/2017. 5 | */ 6 | 7 | public class ApiServerConfiguration { 8 | 9 | private String apiServerUrl; 10 | 11 | ApiServerConfiguration(String apiServerUrl) { 12 | this.apiServerUrl = apiServerUrl; 13 | } 14 | 15 | public String getServerUrl() { 16 | return this.apiServerUrl; 17 | } 18 | 19 | public String getNoteAPIUrl() { 20 | return String.format("%s/note", getServerUrl()); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_http.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hooking.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_network_locked.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_phone_lock.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_warning_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/di/SecureTestApplication.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.di; 2 | 3 | import com.aerogear.androidshowcase.SecureApplication; 4 | 5 | /** 6 | * Setup the DI for the tests. This class will initialise the dagger component for the application. 7 | */ 8 | 9 | public class SecureTestApplication extends SecureApplication { 10 | 11 | SecureApplicationTestComponent component; 12 | 13 | @Override 14 | protected void initInjector() { 15 | component = DaggerSecureApplicationTestComponent.builder().application(this).build(); 16 | component.inject(this); 17 | } 18 | 19 | public SecureApplicationTestComponent getComponent() { 20 | return component; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_not_available_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/push_registration_failed_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/models/User.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.models; 2 | 3 | /** 4 | * Created by tjackman on 01/05/18. 5 | */ 6 | 7 | public class User { 8 | private Long id; 9 | private String name; 10 | private String email; 11 | 12 | public Long getId() { 13 | return id; 14 | } 15 | 16 | public void setId(Long id) { 17 | this.id = id; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public String getEmail() { 29 | return email; 30 | } 31 | 32 | public void setEmail(String email) { 33 | this.email = email; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_active.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/MockTestRunner.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.support.test.runner.AndroidJUnitRunner; 6 | 7 | import com.aerogear.androidshowcase.di.SecureTestApplication; 8 | 9 | /** 10 | * Define the test runner. Override the default Android one as we need use the application class defined by ourselves to setup DI. 11 | */ 12 | 13 | public class MockTestRunner extends AndroidJUnitRunner { 14 | @Override 15 | public Application newApplication(ClassLoader cl, String className, Context context) 16 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 17 | return super.newApplication(cl, SecureTestApplication.class.getName(), context); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/providers/OpenIDAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.providers; 2 | import android.app.Activity; 3 | 4 | import org.aerogear.mobile.core.Callback; 5 | 6 | 7 | /** 8 | * An interface for OpenID Connect Authentication Providers 9 | */ 10 | public interface OpenIDAuthenticationProvider { 11 | 12 | /** 13 | * Perform a login to the OIDC server 14 | * @param fromActivity - the activity to use for authenticating 15 | * @param authCallback - the authentication callback 16 | */ 17 | void login(Activity fromActivity, Callback authCallback); 18 | 19 | /** 20 | * Perform a logout against the OIDC server 21 | * 22 | * @param logoutCallback the logout callback 23 | */ 24 | void logout(Callback logoutCallback); 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/fh_icon.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_push.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/presenters/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.presenters; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import com.aerogear.androidshowcase.mvp.views.AppView; 6 | 7 | /** 8 | * A base implementation for the presenter interface 9 | */ 10 | 11 | public class BasePresenter implements Presenter { 12 | protected VIEW view; 13 | 14 | @Override 15 | public void attachView(@NonNull VIEW view) { 16 | this.view = view; 17 | this.onViewAttached(); 18 | } 19 | 20 | @Override 21 | public void detachView() { 22 | this.view = null; 23 | this.onViewDetached(); 24 | } 25 | 26 | @Override 27 | public void resume() { 28 | 29 | } 30 | 31 | @Override 32 | public void pause() { 33 | 34 | } 35 | 36 | protected void onViewAttached() { 37 | 38 | } 39 | 40 | protected void onViewDetached() { 41 | 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/menu_app_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/configurations/AppConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.configurations; 2 | 3 | import org.aerogear.mobile.core.MobileCore; 4 | import org.aerogear.mobile.core.configuration.ServiceConfiguration; 5 | 6 | import javax.inject.Inject; 7 | import javax.inject.Singleton; 8 | 9 | /** 10 | * Created by weili on 31/10/2017. 11 | */ 12 | @Singleton 13 | public class AppConfiguration { 14 | 15 | private static final String NOTES_SERVER_KEY = "notes-service"; 16 | 17 | private ApiServerConfiguration apiServerConfiguration; 18 | 19 | @Inject 20 | public AppConfiguration() { 21 | readConfigurations(); 22 | } 23 | 24 | private void readConfigurations() { 25 | final ServiceConfiguration serviceConfiguration = MobileCore.getInstance().getServiceConfigurationById(NOTES_SERVER_KEY); 26 | final String serviceUrl = serviceConfiguration.getUrl(); 27 | this.apiServerConfiguration = new ApiServerConfiguration(serviceUrl); 28 | } 29 | 30 | public ApiServerConfiguration getAPIServerConfiguration() { 31 | return this.apiServerConfiguration; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/presenters/Presenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.presenters; 2 | 3 | 4 | import com.aerogear.androidshowcase.mvp.views.AppView; 5 | 6 | /** 7 | * Interface representing a Presenter in a model-view-presenter (MVP) pattern. 8 | * In most cases, the presenter is bound with a view. Given that the view will have its life cycles, the presenter needs to be aware of the view's life cycle. 9 | */ 10 | 11 | public interface Presenter { 12 | 13 | /** 14 | * Attach the view to the presenter 15 | * @param view the view to attach 16 | */ 17 | void attachView(VIEW view); 18 | 19 | /** 20 | * detach the view from the presenter 21 | */ 22 | void detachView(); 23 | 24 | /** 25 | * Method that control the lifecycle of the view. It should be called in the view's 26 | * (Activity or Fragment) onResume() method. 27 | */ 28 | void resume(); 29 | 30 | /** 31 | * Method that control the lifecycle of the view. It should be called in the view's 32 | * (Activity or Fragment) onPause() method. 33 | */ 34 | void pause(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/views/AppView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.views; 2 | 3 | /** 4 | * Interface to represent a View that will load data. 5 | * The data loading should happen in a backgroun thread. 6 | * The View will show/hide the progress indicator accordingly. 7 | */ 8 | 9 | public interface AppView { 10 | 11 | /** 12 | * Show the progress bar to indicate the loading is in progress 13 | */ 14 | void showLoading(); 15 | 16 | /** 17 | * Hide the progress bar 18 | */ 19 | void hideLoading(); 20 | 21 | /** 22 | * Show a message using snackbar 23 | * @param message the message to show 24 | */ 25 | void showMessage(String message); 26 | 27 | /** 28 | * Show a message using snackbar 29 | * @param messageResourceId the resource id of the message 30 | */ 31 | void showMessage(int messageResourceId); 32 | 33 | /** 34 | * Show a message using snackbar 35 | * @param messageResourceId the resource id of the message 36 | * @param formatArgs format arguments 37 | */ 38 | void showMessage(int messageResourceId, Object... formatArgs); 39 | } 40 | -------------------------------------------------------------------------------- /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 /home/tjackman/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -dontwarn com.google.errorprone.annotations.* 27 | -dontwarn okio.** 28 | -dontwarn org.slf4j.** 29 | 30 | -keep class net.sqlcipher.** { 31 | *; 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/documentation/DocumentUrl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.documentation; 2 | 3 | /** 4 | * This class enumerates the documentation pages we have. 5 | */ 6 | public enum DocumentUrl { 7 | PUSH("https://docs.aerogear.org/external/showcase/android/push.html"), 8 | IDENTITY_MANAGEMENT("https://docs.aerogear.org/external/showcase/android/idm.html"), 9 | DEVICE_SECURITY("https://docs.aerogear.org/external/showcase/android/security.html"), 10 | METRICS("https://docs.aerogear.org/external/showcase/android/metrics.html"), 11 | RUNTIME("https://docs.aerogear.org/external/showcase/android/runtime.html"), 12 | IDENTITY_MANAGEMENT_SSO("https://docs.aerogear.org/external/showcase/android/idmsso.html"), 13 | NOTES_SERVICE("https://github.com/feedhenry/mobile-security/tree/master/projects/api-server"), 14 | SELF_SIGNED_DOCS("https://docs.aerogear.org/external/cert/self-signed-cert.html"); 15 | 16 | private final String url; 17 | 18 | DocumentUrl(String urlString) { 19 | this.url = urlString; 20 | 21 | } 22 | 23 | public String getUrl() { 24 | return url; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/push/PushGestureViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.push; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.aerogear.androidshowcase.R; 8 | import com.thesurix.gesturerecycler.GestureViewHolder; 9 | 10 | import butterknife.BindView; 11 | import butterknife.ButterKnife; 12 | 13 | public class PushGestureViewHolder extends GestureViewHolder { 14 | 15 | @Nullable 16 | @BindView(R.id.foreground_view) 17 | View mForegroundView; 18 | 19 | @BindView(R.id.message) 20 | TextView message; 21 | 22 | @BindView(R.id.receivedAt) 23 | TextView receivedAt; 24 | 25 | 26 | public PushGestureViewHolder(View itemView) { 27 | super(itemView); 28 | 29 | ButterKnife.bind(this, itemView); 30 | } 31 | 32 | @Override 33 | public boolean canDrag() { 34 | return false; 35 | } 36 | 37 | @Override 38 | public boolean canSwipe() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public View getForegroundView() { 44 | return mForegroundView; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/utils/StreamUtils.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * Some utility functions to perform IO stream related operations. 9 | */ 10 | 11 | public class StreamUtils { 12 | 13 | /** 14 | * Read UTF8 string from the given input steam. 15 | * @param in the input stream 16 | * @return the string value from the input stream 17 | * @throws IOException 18 | */ 19 | public static String readStream(InputStream in) throws IOException { 20 | byte[] bytes = readStreamBytes(in); 21 | String content = new String(bytes, "utf-8"); 22 | return content; 23 | } 24 | 25 | public static byte[] readStreamBytes(InputStream in) throws IOException { 26 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 27 | byte[] b = new byte[1024]; 28 | int numberOfBytesRead; 29 | while ((numberOfBytesRead = in.read(b)) >= 0) { 30 | baos.write(b, 0, numberOfBytesRead); 31 | } 32 | return baos.toByteArray(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/push/PushGestureAdapter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.push; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.aerogear.androidshowcase.R; 9 | import com.thesurix.gesturerecycler.GestureAdapter; 10 | 11 | public class PushGestureAdapter 12 | extends GestureAdapter { 13 | 14 | @NonNull 15 | @Override 16 | public PushGestureViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 17 | 18 | View view = LayoutInflater 19 | .from(parent.getContext()) 20 | .inflate(R.layout.item_push, parent, false); 21 | 22 | return new PushGestureViewHolder(view); 23 | 24 | } 25 | 26 | @Override 27 | public void onBindViewHolder(@NonNull PushGestureViewHolder holder, int position) { 28 | PushFragment.PushMessage pushMessage = getItem(position); 29 | 30 | holder.message.setText(pushMessage.getMessage()); 31 | holder.receivedAt.setText(pushMessage.getDateReceived()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_notes_list.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/di/SecureApplicationComponent.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.di; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.aerogear.androidshowcase.SecureApplication; 6 | import com.aerogear.androidshowcase.domain.crypto.AesCrypto; 7 | import com.aerogear.androidshowcase.features.authentication.providers.OpenIDAuthenticationProvider; 8 | import dagger.BindsInstance; 9 | import dagger.Component; 10 | import dagger.android.AndroidInjectionModule; 11 | import javax.inject.Singleton; 12 | 13 | /** 14 | * Define the dependencies of the app. Used by Dagger2 to build dependency graph. 15 | */ 16 | @Singleton 17 | @Component(modules = {AndroidInjectionModule.class, SecureApplicationModule.class, 18 | MainActivityModule.class}) 19 | public interface SecureApplicationComponent { 20 | 21 | @Component.Builder 22 | interface Builder { 23 | 24 | @BindsInstance 25 | Builder application(Application application); 26 | 27 | SecureApplicationComponent build(); 28 | } 29 | 30 | void inject(SecureApplication app); 31 | 32 | Context context(); 33 | 34 | AesCrypto provideAesCrypto(); 35 | 36 | OpenIDAuthenticationProvider authProvider(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_area.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Motivation 2 | Add references to relevant tickets or a short description about what motivated you do it. (E.g JIRA: https://issues.jboss.org/browse/AEROGEAR-{} AND/OR ISSUE: https://github.com/aerogear/standards/issues/{}) 3 | 4 | ## What 5 | Add an short answer for: What was done in this PR? (E.g Don't allow users has access to the feature X.) 6 | 7 | ## Why 8 | Add an short answer for: Why it was done? (E.g The feature X was deprecated.) 9 | 10 | ## How 11 | Add an short answer for: How it was done? (E.g By removing this feature from ... OR By removing just the button but not its implementation ... ) 12 | 13 | ## Verification Steps 14 | Add the steps required to check this change. Following an example. 15 | 16 | 1. Go to `XX >> YY >> SS` 17 | 2. Create a new item `N` with the info `X` 18 | 3. Try to edit this item 19 | 4. Check if in the left menu the feature X is not so long present. 20 | 21 | ## Checklist: 22 | 23 | - [ ] Code has been tested locally by PR requester 24 | - [ ] Changes have been successfully verified by another team member 25 | 26 | ## Progress 27 | 28 | - [x] Finished task 29 | - [ ] TODO 30 | 31 | ## Additional Notes 32 | 33 | PS.: Add images and/or .gifs to illustrate what was changed if this pull request modifies the appearance/output of something presented to the users. 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/crypto/SecureKeyStoreImpl.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.crypto; 2 | 3 | import java.io.IOException; 4 | import java.security.GeneralSecurityException; 5 | import java.security.KeyStore; 6 | 7 | /** 8 | * Base class that implements the SecureKeystore interface. 9 | */ 10 | 11 | public abstract class SecureKeyStoreImpl implements SecureKeyStore { 12 | 13 | protected static final String ANDROID_KEY_STORE = "AndroidKeyStore"; 14 | 15 | protected static final int AES_KEYSIZE_128 = 128; 16 | protected static final int RSA_KEY_SIZE = 2048; 17 | 18 | protected static final String ALG_AES_GCM_NOPADDING = "AES/GCM/NoPadding"; 19 | protected static final String ALG_RSA_ECB_PCKS1Padding = "RSA/ECB/PKCS1Padding"; 20 | protected static final String ALG_RSA_ECB_OAEPPadding = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 21 | 22 | protected KeyStore loadKeyStore() throws GeneralSecurityException, IOException { 23 | KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE); 24 | keyStore.load(null); 25 | return keyStore; 26 | } 27 | 28 | @Override 29 | public KeyStore.Entry getKeyPairEntry(String keyAlias) throws GeneralSecurityException, IOException { 30 | KeyStore ks = loadKeyStore(); 31 | return ks.getEntry(keyAlias, null); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "56938872708", 4 | "firebase_url": "https://aerogear-playground.firebaseio.com", 5 | "project_id": "aerogear-playground", 6 | "storage_bucket": "aerogear-playground.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:56938872708:android:1511d73e1e8c02f1", 12 | "android_client_info": { 13 | "package_name": "com.aerogear.androidshowcase" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "56938872708-guthigb9rlncora778hs22ufbkqpjtom.apps.googleusercontent.com", 19 | "client_type": 3 20 | }, 21 | { 22 | "client_id": "56938872708-7f2mrm3edeu8g6iiio78nc96kk7mohet.apps.googleusercontent.com", 23 | "client_type": 3 24 | } 25 | ], 26 | "api_key": [ 27 | { 28 | "current_key": "AIzaSyAAM11RlZfu76uhYcM7QDmxNNS9u9xl4z4" 29 | } 30 | ], 31 | "services": { 32 | "analytics_service": { 33 | "status": 1 34 | }, 35 | "appinvite_service": { 36 | "status": 1, 37 | "other_platform_oauth_client": [] 38 | }, 39 | "ads_service": { 40 | "status": 2 41 | } 42 | } 43 | } 44 | ], 45 | "configuration_version": "1" 46 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/Constants.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain; 2 | 3 | import android.net.Uri; 4 | 5 | /** 6 | * Created by weili on 13/09/2017. 7 | */ 8 | 9 | public class Constants { 10 | 11 | public static final class REQUEST_CODES { 12 | public static final int AUTH_CODE = 1; 13 | } 14 | 15 | public static final class TOKEN_FIELDS { 16 | public static final String AUTH_STATE = "authState"; 17 | public static final String IDENTITY_DATA = "identityData"; 18 | } 19 | 20 | 21 | public static final class OPEN_ID_CONNECT_CONFIG { 22 | public static final Uri REDIRECT_URI = Uri.parse("com.aerogear.androidshowcase:/callback"); 23 | public static final String OPEN_ID_SCOPE = "openid"; 24 | } 25 | 26 | public static final class ACCESS_CONTROL_ROLES { 27 | public static final String ROLE_MOBILE_USER = "mobile-user"; 28 | public static final String ROLE_API_ACCESS = "api-access"; 29 | public static final String ROLE_SUPERUSER = "superuser"; 30 | } 31 | 32 | public static final class NOTE_FIELDS { 33 | public static final String ID_FIELD = "id"; 34 | public static final String TITLE_FIELD = "title"; 35 | public static final String CONTENT_FIELD = "content"; 36 | public static final String STORE_TYPE_FIELD = "storeType"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/RsaCryptoTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.support.test.InstrumentationRegistry; 4 | 5 | import com.aerogear.androidshowcase.di.SecureTestApplication; 6 | import com.aerogear.androidshowcase.domain.crypto.RsaCrypto; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import java.io.IOException; 12 | import java.security.GeneralSecurityException; 13 | 14 | import javax.inject.Inject; 15 | 16 | import static junit.framework.Assert.assertEquals; 17 | 18 | /** 19 | * Created by weili on 27/09/2017. 20 | */ 21 | 22 | public class RsaCryptoTest { 23 | @Inject 24 | RsaCrypto rsaCrytoTest; 25 | 26 | @Before 27 | public void setUp() { 28 | SecureTestApplication application = (SecureTestApplication) InstrumentationRegistry.getTargetContext().getApplicationContext(); 29 | application.getComponent().inject(this); 30 | } 31 | 32 | @Test 33 | public void testCryptoOperations() throws GeneralSecurityException, IOException { 34 | String testKeyAlias = "RSACryptoTestKey"; 35 | String textToEncrypt = "this is a test text"; 36 | byte[] encrypted = rsaCrytoTest.encrypt(testKeyAlias,textToEncrypt.getBytes("utf-8")); 37 | byte[] decrypted = rsaCrytoTest.decrypt(testKeyAlias, encrypted); 38 | assertEquals(textToEncrypt, new String(decrypted, "utf-8")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/domain/store/sqlite/SqliteNoteStoreTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.store.sqlite; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | 6 | import com.aerogear.androidshowcase.di.SecureTestApplication; 7 | import com.aerogear.androidshowcase.domain.store.NoteStoreTestBase; 8 | 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import javax.inject.Inject; 14 | 15 | import static junit.framework.Assert.assertEquals; 16 | import static junit.framework.Assert.assertNotNull; 17 | 18 | public class SqliteNoteStoreTest extends NoteStoreTestBase { 19 | 20 | @Inject 21 | Context context; 22 | 23 | @Inject 24 | SqliteNoteStore sqliteStore; 25 | 26 | @Before 27 | public void setup() { 28 | SecureTestApplication application = (SecureTestApplication) InstrumentationRegistry.getTargetContext().getApplicationContext(); 29 | application.getComponent().inject(this); 30 | cleardb(); 31 | } 32 | 33 | @After 34 | public void teardown() { 35 | cleardb(); 36 | } 37 | 38 | @Test 39 | public void testSqliteNoteStore() throws Exception { 40 | noteCRUDL(this.sqliteStore); 41 | } 42 | 43 | private void cleardb() { 44 | this.context.deleteDatabase(NoteDbHelper.DATABASE_NAME); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error_background.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/presenters/AuthenticationDetailsPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.presenters; 2 | 3 | import com.aerogear.androidshowcase.MainActivity; 4 | import com.aerogear.androidshowcase.features.authentication.providers.OpenIDAuthenticationProvider; 5 | import com.aerogear.androidshowcase.features.authentication.views.AuthenticationDetailsView; 6 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 7 | import org.aerogear.mobile.auth.user.UserPrincipal; 8 | import org.aerogear.mobile.core.Callback; 9 | 10 | import javax.inject.Inject; 11 | 12 | /** 13 | * Created by weili on 12/09/2017. 14 | */ 15 | 16 | public class AuthenticationDetailsPresenter extends BasePresenter { 17 | 18 | OpenIDAuthenticationProvider authProvider; 19 | MainActivity mainActivity; 20 | 21 | @Inject 22 | public AuthenticationDetailsPresenter(OpenIDAuthenticationProvider authProviderImpl, MainActivity mainActivity) { 23 | this.authProvider = authProviderImpl; 24 | this.mainActivity = mainActivity; 25 | } 26 | 27 | public void logout(){ 28 | authProvider.logout(new Callback() { 29 | @Override 30 | public void onSuccess(UserPrincipal user) { 31 | view.logoutSuccess(user); 32 | } 33 | 34 | @Override 35 | public void onError(Throwable error) { 36 | view.logoutFailure((Exception) error); 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/authentication/presenters/AuthenticationViewPresenter.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.authentication.presenters; 2 | 3 | import com.aerogear.androidshowcase.MainActivity; 4 | import com.aerogear.androidshowcase.features.authentication.providers.OpenIDAuthenticationProvider; 5 | import com.aerogear.androidshowcase.features.authentication.views.AuthenticationView; 6 | import com.aerogear.androidshowcase.mvp.presenters.BasePresenter; 7 | 8 | import org.aerogear.mobile.auth.user.UserPrincipal; 9 | import org.aerogear.mobile.core.Callback; 10 | 11 | import javax.inject.Inject; 12 | 13 | /** 14 | * Created by weili on 12/09/2017. 15 | */ 16 | 17 | public class AuthenticationViewPresenter extends BasePresenter { 18 | 19 | OpenIDAuthenticationProvider authProvider; 20 | MainActivity mainActivity; 21 | 22 | @Inject 23 | public AuthenticationViewPresenter(OpenIDAuthenticationProvider authProviderImpl, MainActivity mainActivity) { 24 | this.authProvider = authProviderImpl; 25 | this.mainActivity = mainActivity; 26 | } 27 | 28 | public void doLogin() { 29 | authProvider.login(mainActivity, new Callback() { 30 | @Override 31 | public void onSuccess(UserPrincipal user) { 32 | view.renderIdentityInfo(user); 33 | } 34 | 35 | @Override 36 | public void onError(Throwable error) { 37 | view.showAuthError((Exception) error); 38 | } 39 | }); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/domain/store/SecureFileNoteStoreTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.store; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | 6 | import com.aerogear.androidshowcase.di.SecureTestApplication; 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import java.io.File; 13 | 14 | import javax.inject.Inject; 15 | 16 | /** 17 | * Created by weili on 25/09/2017. 18 | */ 19 | 20 | public class SecureFileNoteStoreTest extends NoteStoreTestBase { 21 | @Inject 22 | Context context; 23 | 24 | @Inject 25 | SecureFileNoteStore secureFileNoteStore; 26 | 27 | @Before 28 | public void setup() { 29 | SecureTestApplication application = (SecureTestApplication) InstrumentationRegistry.getTargetContext().getApplicationContext(); 30 | application.getComponent().inject(this); 31 | removeFiles(this.context); 32 | } 33 | 34 | @After 35 | public void teardown() { 36 | removeFiles(this.context); 37 | } 38 | 39 | @Test 40 | public void testSecureFileNoteStore() throws Exception { 41 | noteCRUDL(this.secureFileNoteStore); 42 | } 43 | 44 | public static void removeFiles(Context context) { 45 | File testDir = context.getFilesDir(); 46 | if (testDir.exists()) { 47 | File[] files = testDir.listFiles(); 48 | for (File f : files) { 49 | f.delete(); 50 | } 51 | testDir.delete(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/crypto/RsaCrypto.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.crypto; 2 | 3 | import java.io.IOException; 4 | import java.security.GeneralSecurityException; 5 | import java.security.KeyStore; 6 | 7 | import javax.inject.Inject; 8 | 9 | /** 10 | * Perform data encryption/decryption using RSA key pairs. It can be used to encrypt/decrypt small amount of data. 11 | */ 12 | public class RsaCrypto { 13 | 14 | 15 | SecureKeyStore secureKeyStore; 16 | 17 | @Inject 18 | public RsaCrypto(SecureKeyStore secureKeyStore) { 19 | this.secureKeyStore = secureKeyStore; 20 | } 21 | 22 | public byte[] encrypt(String keyAlias, byte[] textToEncrypt) throws GeneralSecurityException, IOException { 23 | if (!secureKeyStore.hasKeyPair(keyAlias)) { 24 | secureKeyStore.generatePrivateKeyPair(keyAlias); 25 | } 26 | KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) secureKeyStore.getKeyPairEntry(keyAlias); 27 | return RsaHelper.encrypt(secureKeyStore.getSupportedRSAMode(), privateKeyEntry, textToEncrypt); 28 | } 29 | 30 | public byte[] decrypt(String keyAlias, byte[] dataToDecrypt) throws GeneralSecurityException, IOException { 31 | if (!secureKeyStore.hasKeyPair(keyAlias)) { 32 | throw new GeneralSecurityException("missing key " + keyAlias); 33 | } 34 | KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) secureKeyStore.getKeyPairEntry(keyAlias); 35 | return RsaHelper.decrypt(secureKeyStore.getSupportedRSAMode(), privateKeyEntry, dataToDecrypt); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/components/ProgressDialogHelper.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.components; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | 6 | /** 7 | * A helper class to hide/show the progress dialog 8 | */ 9 | 10 | public class ProgressDialogHelper { 11 | private ProgressDialog dialog; 12 | 13 | private volatile int progressesCount = 0; 14 | 15 | public void showProgress(Context context) { 16 | showProgress(context, null); 17 | } 18 | 19 | public void showProgress(Context context, String message) { 20 | showProgress(context, message, null); 21 | } 22 | 23 | public void showProgress(Context context, String message, String title) { 24 | if (context == null) { 25 | return; 26 | } 27 | 28 | if (!inProgress()) { 29 | dialog = new ProgressDialog(context); 30 | if (message != null) dialog.setMessage(message); 31 | if (title != null) dialog.setTitle(title); 32 | dialog.setIndeterminate(true); 33 | dialog.setCanceledOnTouchOutside(false); 34 | dialog.show(); 35 | } 36 | 37 | progressesCount++; 38 | } 39 | 40 | public void hideProgress() { 41 | progressesCount--; 42 | if (progressesCount <= 0) { 43 | if (dialog != null && dialog.isShowing()) { 44 | dialog.dismiss(); 45 | } 46 | progressesCount = 0; 47 | } 48 | 49 | } 50 | 51 | private boolean inProgress() { 52 | return dialog != null && dialog.isShowing(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_landing.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 15 | 16 | 25 | 26 | 27 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_note.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 | 18 | 19 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/views/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.views; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.View; 7 | 8 | import com.aerogear.androidshowcase.mvp.presenters.Presenter; 9 | 10 | /** 11 | * Base fragment. It implements the methods to make sure the presenter and view are initialised correctly, make sure the presenter will get notified about various life cycle events of the fragment. 12 | */ 13 | 14 | public abstract class BaseFragment, VIEW extends AppView> extends Fragment { 15 | protected PRESENTER presenter; 16 | 17 | protected VIEW view; 18 | 19 | @Override 20 | public void onCreate(@Nullable Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | presenter = initPresenter(); 23 | view = initView(); 24 | } 25 | 26 | @Override 27 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 28 | super.onViewCreated(view, savedInstanceState); 29 | presenter.attachView(this.view); 30 | } 31 | 32 | @Override 33 | public void onResume() { 34 | super.onResume(); 35 | presenter.resume(); 36 | } 37 | 38 | @Override 39 | public void onPause() { 40 | super.onPause(); 41 | presenter.pause(); 42 | } 43 | 44 | @Override 45 | public void onDestroyView() { 46 | super.onDestroyView(); 47 | presenter.detachView(); 48 | } 49 | 50 | protected abstract PRESENTER initPresenter(); 51 | 52 | protected abstract VIEW initView(); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/code 5 | docker: 6 | - image: circleci/android:api-27-alpha 7 | environment: 8 | JVM_OPTS: -Xmx3200m 9 | steps: 10 | - checkout 11 | - restore_cache: 12 | key: jars-{{ checksum "build.gradle" }} 13 | - run: 14 | name: Chmod permissions 15 | command: sudo chmod +x ./gradlew 16 | - save_cache: 17 | paths: 18 | - ~/.gradle 19 | key: jars-{{ checksum "build.gradle" }} 20 | - run: 21 | name: Run Tests 22 | command: ./gradlew compileReleaseSources 23 | 24 | pushToKryptoWire: 25 | working_directory: ~/code 26 | docker: 27 | - image: circleci/android:api-27-alpha 28 | environment: 29 | JVM_OPTS: -Xmx3200m 30 | steps: 31 | - checkout 32 | - restore_cache: 33 | key: jars-{{ checksum "build.gradle" }} 34 | - run: 35 | name: Chmod permissions 36 | command: sudo chmod +x ./gradlew 37 | - save_cache: 38 | paths: 39 | - ~/.gradle 40 | key: jars-{{ checksum "build.gradle" }} 41 | - run: 42 | name: Build Release 43 | command: ./gradlew aR 44 | - run: 45 | name: Push To Kryptowire 46 | command: curl -X POST "https://emm.kryptowire.com/api/submit" -F app=@./app/build/outputs/apk/release/app-release.apk -F key=$KRYPTOWIRE_API_KEY -F platform=android 47 | 48 | workflows: 49 | version: 2 50 | build-and-push: 51 | jobs: 52 | - build 53 | - pushToKryptoWire: 54 | filters: 55 | branches: 56 | only: 57 | - master 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 18 | 19 | 30 | 31 | 36 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/SecureApplication.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.databinding.ObservableArrayList; 6 | import android.databinding.ObservableList; 7 | 8 | import com.aerogear.androidshowcase.di.DaggerSecureApplicationComponent; 9 | import com.aerogear.androidshowcase.features.push.PushFragment.PushMessage; 10 | 11 | import net.sqlcipher.database.SQLiteDatabase; 12 | 13 | import javax.inject.Inject; 14 | 15 | import dagger.android.AndroidInjector; 16 | import dagger.android.DispatchingAndroidInjector; 17 | import dagger.android.HasActivityInjector; 18 | 19 | /** 20 | * The main application class. Needs to setup dependency injection. 21 | */ 22 | 23 | public class SecureApplication extends Application implements HasActivityInjector { 24 | 25 | private ObservableList pushMessagesReceived = new ObservableArrayList<>(); 26 | 27 | @Inject 28 | DispatchingAndroidInjector dispatchingAndroidInjector; 29 | 30 | @Override 31 | public void onCreate() { 32 | super.onCreate(); 33 | initInjector(); 34 | 35 | try { 36 | SQLiteDatabase.loadLibs(this); 37 | } catch (UnsatisfiedLinkError e) { 38 | //only thrown during tests, ignore it 39 | } 40 | } 41 | 42 | protected void initInjector() { 43 | DaggerSecureApplicationComponent 44 | .builder() 45 | .application(this) 46 | .build() 47 | .inject(this); 48 | } 49 | 50 | @Override 51 | public AndroidInjector activityInjector() { 52 | return dispatchingAndroidInjector; 53 | } 54 | 55 | public ObservableList getPushMessagesReceived() { 56 | return pushMessagesReceived; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/di/FragmentModules.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.di; 2 | 3 | 4 | import com.aerogear.androidshowcase.features.authentication.AuthenticationDetailsFragment; 5 | import com.aerogear.androidshowcase.features.authentication.AuthenticationFragment; 6 | import com.aerogear.androidshowcase.features.device.DeviceFragment; 7 | import com.aerogear.androidshowcase.features.documentation.DocumentationFragment; 8 | import com.aerogear.androidshowcase.features.home.HomeFragment; 9 | import com.aerogear.androidshowcase.features.landing.LandingFragment; 10 | import com.aerogear.androidshowcase.features.push.PushFragment; 11 | import com.aerogear.androidshowcase.features.underconstruction.UnderConstructionFragment; 12 | 13 | import dagger.Module; 14 | import dagger.android.ContributesAndroidInjector; 15 | 16 | /** 17 | * Define dependencies used by the NotesListFragment. Used by Dagger2 to build dependency graph. 18 | */ 19 | 20 | @Module 21 | public abstract class FragmentModules { 22 | 23 | @ContributesAndroidInjector 24 | abstract HomeFragment contributeHomeFragmentInjector(); 25 | 26 | @ContributesAndroidInjector 27 | abstract AuthenticationFragment contributeAuthenticationFragmentInjector(); 28 | 29 | @ContributesAndroidInjector 30 | abstract AuthenticationDetailsFragment contributeAuthenticationDetailsFragmentInjector(); 31 | 32 | @ContributesAndroidInjector 33 | abstract DeviceFragment contributeDeviceFragmentInjector(); 34 | 35 | @ContributesAndroidInjector 36 | abstract PushFragment contributePushFragmentInjector(); 37 | 38 | @ContributesAndroidInjector 39 | abstract DocumentationFragment contributeDocumentationFragmentInjector(); 40 | 41 | @ContributesAndroidInjector 42 | abstract UnderConstructionFragment contributeUnderConstructionFragmentInjector(); 43 | 44 | @ContributesAndroidInjector 45 | abstract LandingFragment contributeLandingFragmentInjector(); 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/home/HomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.home; 2 | 3 | 4 | import android.app.Activity; 5 | import android.os.Bundle; 6 | import android.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.aerogear.androidshowcase.R; 12 | import com.aerogear.androidshowcase.features.home.presenters.HomeViewPresenter; 13 | import com.aerogear.androidshowcase.features.home.views.HomeView; 14 | import com.aerogear.androidshowcase.features.home.views.HomeViewImpl; 15 | import com.aerogear.androidshowcase.mvp.views.BaseFragment; 16 | 17 | import javax.inject.Inject; 18 | 19 | import dagger.android.AndroidInjection; 20 | 21 | /** 22 | * A simple {@link Fragment} subclass. 23 | */ 24 | public class HomeFragment extends BaseFragment { 25 | 26 | public static final String TAG = "home"; 27 | 28 | @Inject 29 | HomeViewPresenter homeViewPresenter; 30 | 31 | public HomeFragment() { 32 | // Required empty public constructor 33 | } 34 | 35 | 36 | @Override 37 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 38 | Bundle savedInstanceState) { 39 | 40 | // Inflate the layout for this fragment 41 | return inflater.inflate(R.layout.fragment_home, container, false); 42 | } 43 | 44 | @Override 45 | public void onAttach(Activity activity) { 46 | AndroidInjection.inject(this); 47 | super.onAttach(activity); 48 | } 49 | 50 | @Override 51 | public void onDetach() { 52 | super.onDetach(); 53 | this.homeViewPresenter = null; 54 | } 55 | 56 | @Override 57 | protected HomeViewPresenter initPresenter() { 58 | return homeViewPresenter; 59 | } 60 | 61 | @Override 62 | protected HomeView initView() { 63 | return new HomeViewImpl(this) {}; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/MainActivityInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.support.test.rule.ActivityTestRule; 4 | import android.support.test.runner.AndroidJUnit4; 5 | 6 | import org.junit.Before; 7 | import org.junit.Rule; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static android.support.test.espresso.Espresso.onView; 12 | import static android.support.test.espresso.action.ViewActions.click; 13 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 14 | import static android.support.test.espresso.contrib.DrawerActions.open; 15 | import static android.support.test.espresso.contrib.DrawerMatchers.isClosed; 16 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 17 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 18 | import static android.support.test.espresso.matcher.ViewMatchers.withText; 19 | 20 | /** 21 | * Instrumentation test, which will execute on an Android device. 22 | * 23 | * @see Testing documentation 24 | */ 25 | @RunWith(AndroidJUnit4.class) 26 | public class MainActivityInstrumentedTest { 27 | 28 | @Rule 29 | public ActivityTestRule activityRule = new ActivityTestRule(MainActivity.class); 30 | 31 | @Test 32 | public void homeViewDisplayed() throws Exception { 33 | onView(withId(R.id.home_title)).check(matches(isDisplayed())); 34 | onView(withId(R.id.drawer_layout)).check(matches(isClosed())); 35 | } 36 | 37 | @Test 38 | public void appNavigation() throws Exception { 39 | onView(withId(R.id.drawer_layout)).perform(open()); 40 | navigateTo(R.string.fragment_title_authenticate, R.id.keycloakLogin); 41 | } 42 | 43 | private void navigateTo(final int titleId, final int fragmentId) throws Exception { 44 | onView(withText(titleId)).perform(click()); 45 | onView(withId(fragmentId)).check(matches(isDisplayed())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/providers/PushServiceProvider.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.providers; 2 | 3 | import com.aerogear.androidshowcase.R; 4 | 5 | import org.aerogear.mobile.core.MobileCore; 6 | import org.aerogear.mobile.core.executor.AppExecutors; 7 | import org.aerogear.mobile.core.reactive.Responder; 8 | import org.aerogear.mobile.push.PushService; 9 | import org.aerogear.mobile.push.UnifiedPushConfig; 10 | 11 | import java.util.Arrays; 12 | 13 | public class PushServiceProvider { 14 | 15 | private static PushServiceProvider instance; 16 | 17 | private PushService pushService; 18 | private Exception registrationException; 19 | 20 | protected PushServiceProvider() { 21 | pushService = new PushService.Builder().openshift().build(); 22 | } 23 | 24 | /** 25 | * Register the push service. 26 | */ 27 | public void registerDevice() { 28 | pushService.registerDevice().respondOn(new AppExecutors().singleThreadService()) 29 | .respondWith(new Responder() { 30 | @Override 31 | public void onResult(Boolean value) { 32 | MobileCore.getLogger().info(String.valueOf(R.string.push_device_register_success)); 33 | } 34 | 35 | @Override 36 | public void onException(Exception exception) { 37 | MobileCore.getLogger().error(exception.getMessage(), exception); 38 | registrationException = exception; 39 | } 40 | }); 41 | } 42 | 43 | /** 44 | * Retrieve the exception that occurred during registration, if any. 45 | * @return The exception that occurred during registration, or null. 46 | */ 47 | public Exception getRegistrationException() { 48 | return this.registrationException; 49 | } 50 | 51 | public static PushServiceProvider getInstance() { 52 | if(instance == null) { 53 | instance = new PushServiceProvider(); 54 | } 55 | return instance; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/mvp/views/BaseAppView.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.mvp.views; 2 | 3 | import android.app.Fragment; 4 | import android.content.Context; 5 | import android.support.design.widget.Snackbar; 6 | 7 | import com.aerogear.androidshowcase.R; 8 | import com.aerogear.androidshowcase.mvp.components.ProgressDialogHelper; 9 | 10 | /** 11 | * A base implementation for the AppView interface. 12 | */ 13 | 14 | public abstract class BaseAppView implements AppView { 15 | 16 | private Fragment fragment; 17 | private ProgressDialogHelper progressDialogHelper; 18 | 19 | public BaseAppView(Fragment fragment) { 20 | this.fragment = fragment; 21 | this.progressDialogHelper = new ProgressDialogHelper(); 22 | 23 | } 24 | 25 | @Override 26 | public void showLoading() { 27 | Context ctx = getContext(); 28 | if (ctx != null) { 29 | this.progressDialogHelper.showProgress(ctx); 30 | } 31 | } 32 | 33 | @Override 34 | public void hideLoading() { 35 | this.progressDialogHelper.hideProgress(); 36 | } 37 | 38 | @Override 39 | public void showMessage(String message) { 40 | Context ctx = getContext(); 41 | if (ctx != null) { 42 | Snackbar snackbar = Snackbar.make(this.fragment.getActivity().getCurrentFocus(), message, Snackbar.LENGTH_SHORT) 43 | .setAction("Action", null); 44 | snackbar.getView().setBackgroundResource(R.color.white); 45 | snackbar.show(); 46 | } 47 | } 48 | 49 | @Override 50 | public void showMessage(int messageResId) { 51 | Context ctx = getContext(); 52 | showMessage(ctx.getString(messageResId)); 53 | } 54 | 55 | @Override 56 | public void showMessage(int messageResourceId, Object... formatArgs) { 57 | Context ctx = getContext(); 58 | showMessage(ctx.getString(messageResourceId, formatArgs)); 59 | } 60 | 61 | private Context getContext() { 62 | return this.fragment.getActivity(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/domain/store/NoteStoreTestBase.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.store; 2 | 3 | import com.aerogear.androidshowcase.domain.models.Note; 4 | 5 | import java.util.List; 6 | 7 | import static junit.framework.Assert.assertEquals; 8 | import static junit.framework.Assert.assertNotNull; 9 | 10 | /** 11 | * Created by weili on 25/09/2017. 12 | */ 13 | 14 | public class NoteStoreTestBase { 15 | 16 | protected void noteCRUDL(NoteDataStore noteStore) throws Exception { 17 | String noteTitle = "testNoteTitle"; 18 | String noteContent = "this is a test note"; 19 | //make sure no existing notes 20 | Note testNote = new Note(noteTitle, noteContent); 21 | List notes = noteStore.listNotes(); 22 | assertEquals(0, notes.size()); 23 | 24 | //create a note 25 | Note created = noteStore.createNote(testNote); 26 | assertNotNull(created); 27 | notes = noteStore.listNotes(); 28 | assertEquals(1, notes.size()); 29 | Note firstNoteInList = notes.get(0); 30 | assertNotNull(firstNoteInList.getId()); 31 | assertNotNull(firstNoteInList.getTitle()); 32 | assertNotNull(firstNoteInList.getCreatedAt()); 33 | 34 | //read a note 35 | Note readNote = noteStore.readNote(testNote.getId()); 36 | assertNotNull(readNote); 37 | assertEquals(readNote.getTitle(), testNote.getTitle()); 38 | assertEquals(readNote.getContent(), testNote.getContent()); 39 | assertEquals(readNote.getId(), testNote.getId()); 40 | 41 | //update a note 42 | String titleUpdate = "testNoteTitleUpdated"; 43 | testNote.setTitle(titleUpdate); 44 | Note updatedNote = noteStore.updateNote(testNote); 45 | assertNotNull(updatedNote); 46 | readNote = noteStore.readNote(testNote.getId()); 47 | assertEquals(readNote.getTitle(), titleUpdate); 48 | 49 | //delete a note 50 | noteStore.deleteNote(testNote); 51 | notes = noteStore.listNotes(); 52 | assertEquals(0, notes.size()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/device/views/WarningDialog.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.device.views; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.annotation.Nullable; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.aerogear.androidshowcase.R; 14 | 15 | public class WarningDialog extends DialogFragment { 16 | int SCORE_THRESHOLD; 17 | int trustScore; 18 | 19 | @Nullable 20 | @Override 21 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 22 | View view = super.onCreateView(inflater, container, savedInstanceState); 23 | getDialog().setCanceledOnTouchOutside(false); 24 | return view; 25 | } 26 | 27 | @Override 28 | public Dialog onCreateDialog(Bundle savedInstanceState) { 29 | // Use the Builder class for convenient dialog construction 30 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 31 | SCORE_THRESHOLD = getArguments().getInt("SCORE_THRESHOLD"); 32 | trustScore = getArguments().getInt("trustScore"); 33 | builder.setTitle("Warning"); 34 | builder.setMessage("Your current device trust score " + trustScore + "% is below the specified target of " + SCORE_THRESHOLD + "%, do you want to continue or exit the app?") 35 | .setPositiveButton(R.string.device_exit, new DialogInterface.OnClickListener() { 36 | public void onClick(DialogInterface dialog, int id) { 37 | android.os.Process.killProcess(android.os.Process.myPid()); 38 | } 39 | }) 40 | .setNegativeButton(R.string.device_continue, new DialogInterface.OnClickListener() { 41 | public void onClick(DialogInterface dialog, int id) { 42 | dismiss(); 43 | } 44 | }); 45 | return builder.create(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/features/underconstruction/UnderConstructionFragment.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.features.underconstruction; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.aerogear.androidshowcase.R; 11 | import com.aerogear.androidshowcase.features.push.presenters.PushPresenter; 12 | import com.aerogear.androidshowcase.features.underconstruction.presenters.UnderConstructionPresenter; 13 | import com.aerogear.androidshowcase.features.underconstruction.views.UnderConstructionViewImpl; 14 | import com.aerogear.androidshowcase.mvp.presenters.Presenter; 15 | import com.aerogear.androidshowcase.mvp.views.AppView; 16 | import com.aerogear.androidshowcase.mvp.views.BaseFragment; 17 | 18 | import javax.inject.Inject; 19 | 20 | import butterknife.ButterKnife; 21 | import dagger.android.AndroidInjection; 22 | 23 | public class UnderConstructionFragment extends BaseFragment { 24 | 25 | public static final String TAG = "UnderConstruction"; 26 | 27 | @Inject 28 | UnderConstructionPresenter underConstructionPresenter; 29 | 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 33 | Bundle savedInstanceState) { 34 | View view = inflater.inflate(R.layout.fragment_under_construction, container, false); 35 | 36 | ButterKnife.bind(this, view); 37 | 38 | return view; 39 | } 40 | 41 | @Override 42 | public void onAttach(Activity activity) { 43 | AndroidInjection.inject(this); 44 | super.onAttach(activity); 45 | } 46 | 47 | @Override 48 | public void onDetach() { 49 | super.onDetach(); 50 | this.underConstructionPresenter = null; 51 | } 52 | 53 | @Override 54 | protected Presenter initPresenter() { 55 | return underConstructionPresenter; 56 | } 57 | 58 | @Override 59 | protected AppView initView() { 60 | return new UnderConstructionViewImpl(this) { 61 | }; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/CertificateErrorDialog.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.support.annotation.Nullable; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | public class CertificateErrorDialog extends DialogFragment { 14 | 15 | 16 | private Runnable gotoDocs; 17 | 18 | @Nullable 19 | @Override 20 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 21 | View view = super.onCreateView(inflater, container, savedInstanceState); 22 | getDialog().setCanceledOnTouchOutside(false); 23 | return view; 24 | } 25 | 26 | @Override 27 | public Dialog onCreateDialog(Bundle savedInstanceState) { 28 | // Use the Builder class for convenient dialog construction 29 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 30 | builder.setTitle("Certificate Error"); 31 | builder.setMessage("You may be using self signed certificates that will prevent the showcase from running properly. Please review the documentation and configure your certificates.") 32 | .setPositiveButton("Show Documentation", new DialogInterface.OnClickListener() { 33 | public void onClick(DialogInterface dialog, int id) { 34 | if (gotoDocs != null) { 35 | gotoDocs.run(); 36 | } else { 37 | dismiss(); 38 | } 39 | } 40 | }) 41 | .setNegativeButton("Close", new DialogInterface.OnClickListener() { 42 | public void onClick(DialogInterface dialog, int id) { 43 | dismiss(); 44 | } 45 | }); 46 | return builder.create(); 47 | } 48 | 49 | public void setGotoDocs(Runnable runnable) { 50 | this.gotoDocs = runnable; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/di/SecureApplicationTestComponent.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.di; 2 | 3 | import android.content.Context; 4 | 5 | import com.aerogear.androidshowcase.AesCryptoTest; 6 | import com.aerogear.androidshowcase.RsaCryptoTest; 7 | import com.aerogear.androidshowcase.StorageFeatureTest; 8 | import com.aerogear.androidshowcase.domain.repositories.NoteRepository; 9 | import com.aerogear.androidshowcase.domain.store.NoteDataStoreFactory; 10 | import com.aerogear.androidshowcase.domain.store.SecureFileNoteStoreTest; 11 | import com.aerogear.androidshowcase.domain.store.sqlite.SqliteNoteStoreTest; 12 | import com.aerogear.androidshowcase.features.authentication.providers.OpenIDAuthenticationProvider; 13 | 14 | import javax.inject.Singleton; 15 | 16 | import dagger.BindsInstance; 17 | import dagger.Component; 18 | import dagger.android.AndroidInjectionModule; 19 | 20 | /** 21 | * Define the DI graph for Dagger for the tests. You will need to add new methods into this interface if new tests are added and then need DI. 22 | */ 23 | @Singleton 24 | @Component(modules = {AndroidInjectionModule.class, SecureApplicationTestModule.class, MainActivityModule.class}) 25 | public interface SecureApplicationTestComponent { 26 | @Component.Builder 27 | interface Builder { 28 | @BindsInstance 29 | SecureApplicationTestComponent.Builder application(SecureTestApplication application); 30 | 31 | SecureApplicationTestComponent build(); 32 | } 33 | 34 | void inject(SecureTestApplication app); 35 | 36 | //when a new test is added, if it needs DI, please add a new "inject" method here. The argument should be an instance of the test. 37 | //Then in the test itself, make sure call this method during setup. See StorageFeatureTest for example. 38 | void inject(StorageFeatureTest fragmentTest); 39 | void inject(AesCryptoTest cryptoTest); 40 | void inject(RsaCryptoTest rsaTest); 41 | void inject(SqliteNoteStoreTest noteStoreTest); 42 | void inject(SecureFileNoteStoreTest fileNoteStoreTest); 43 | 44 | Context context(); 45 | NoteDataStoreFactory provideNoteDataStoreFactory(); 46 | NoteRepository noteRepository(); 47 | OpenIDAuthenticationProvider authProvider(); 48 | } 49 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/aerogear/androidshowcase/AesCryptoTest.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase; 2 | 3 | import android.support.test.InstrumentationRegistry; 4 | 5 | import com.aerogear.androidshowcase.di.SecureTestApplication; 6 | import com.aerogear.androidshowcase.domain.crypto.AesCrypto; 7 | import com.aerogear.androidshowcase.domain.utils.StreamUtils; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import java.io.ByteArrayInputStream; 13 | import java.io.ByteArrayOutputStream; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | import java.security.GeneralSecurityException; 18 | 19 | import javax.inject.Inject; 20 | 21 | import static junit.framework.Assert.assertEquals; 22 | 23 | /** 24 | * Created by weili on 22/09/2017. 25 | */ 26 | 27 | public class AesCryptoTest { 28 | 29 | @Inject 30 | AesCrypto cryptoToTest; 31 | 32 | @Before 33 | public void setUp() { 34 | SecureTestApplication application = (SecureTestApplication) InstrumentationRegistry.getTargetContext().getApplicationContext(); 35 | application.getComponent().inject(this); 36 | } 37 | 38 | @Test 39 | public void testCryptoOperations() throws GeneralSecurityException, IOException { 40 | String testKeyAlias = "AesGcmCryptoTestKey"; 41 | String textToEncrypt = "this is a test text"; 42 | String encryptedText = cryptoToTest.encryptString(testKeyAlias, textToEncrypt, "utf-8"); 43 | String decryptedText = cryptoToTest.decryptString(testKeyAlias, encryptedText, "utf-8"); 44 | assertEquals(textToEncrypt, decryptedText); 45 | 46 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 47 | OutputStream cipherStream = cryptoToTest.encryptStream(testKeyAlias, bos); 48 | cipherStream.write(textToEncrypt.getBytes()); 49 | cipherStream.flush(); 50 | cipherStream.close(); 51 | byte[] encryptedBytes = bos.toByteArray(); 52 | ByteArrayInputStream bis = new ByteArrayInputStream(encryptedBytes); 53 | InputStream decryptedStream = cryptoToTest.decryptStream(testKeyAlias, bis); 54 | String decryptedTextFromStream = StreamUtils.readStream(decryptedStream); 55 | assertEquals(textToEncrypt, decryptedTextFromStream); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/menu_nav_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 25 | 26 | 37 | 38 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/aerogear/androidshowcase/domain/crypto/NullAndroidSecureKeyStore.java: -------------------------------------------------------------------------------- 1 | package com.aerogear.androidshowcase.domain.crypto; 2 | 3 | import java.io.IOException; 4 | import java.security.GeneralSecurityException; 5 | import java.security.Key; 6 | import java.security.KeyStore; 7 | 8 | /** 9 | * A implementation of the SecureKeyStore interface that will only throw exceptions. 10 | * This should only be used for devices with Android that is lower than 18 (4.3). 11 | */ 12 | 13 | public class NullAndroidSecureKeyStore extends SecureKeyStoreImpl implements SecureKeyStore { 14 | @Override 15 | public String getSupportedAESMode() { 16 | return null; 17 | } 18 | 19 | @Override 20 | public String getSupportedRSAMode() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public boolean hasSecretKey(String keyAlias) throws GeneralSecurityException, IOException { 26 | throw new GeneralSecurityException("This version of Android is not supported"); 27 | } 28 | 29 | @Override 30 | public Key getSecretKey(String keyAlias) throws GeneralSecurityException, IOException { 31 | throw new GeneralSecurityException("This version of Android is not supported"); 32 | } 33 | 34 | @Override 35 | public void generateAESKey(String keyAlias) throws GeneralSecurityException, IOException { 36 | throw new GeneralSecurityException("This version of Android is not supported"); 37 | } 38 | 39 | @Override 40 | public void generatePrivateKeyPair(String keyAlias) throws GeneralSecurityException, IOException { 41 | throw new GeneralSecurityException("This version of Android is not supported"); 42 | } 43 | 44 | @Override 45 | public KeyStore.Entry getKeyPairEntry(String keyAlias) throws GeneralSecurityException, IOException { 46 | throw new GeneralSecurityException("This version of Android is not supported"); 47 | } 48 | 49 | @Override 50 | public boolean hasKeyPair(String keyAlias) throws GeneralSecurityException, IOException { 51 | throw new GeneralSecurityException("This version of Android is not supported"); 52 | } 53 | 54 | @Override 55 | public void deleteKey(String keyAlias) throws GeneralSecurityException, IOException { 56 | throw new GeneralSecurityException("This version of Android is not supported"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /** 2 | * Android Jenkinsfile 3 | */ 4 | node("android"){ 5 | stage("Checkout"){ 6 | checkout scm 7 | } 8 | 9 | stage ("Prepare"){ 10 | sh 'chmod +x ./gradlew' 11 | } 12 | 13 | stage("Build"){ 14 | if (params.BUILD_CONFIG == 'release') { 15 | sh './gradlew clean assembleRelease' // builds app/build/outputs/apk/app-release.apk file 16 | } else { 17 | sh './gradlew clean assembleDebug' // builds app/build/outputs/apk/app-debug.apk 18 | } 19 | } 20 | 21 | def keyStoreId = params.BUILD_CREDENTIAL_ID 22 | def keyAlias = params.BUILD_CREDENTIAL_ALIAS ?: '' 23 | // Uncomment this stage if your keystore is external to your source code. 24 | // stage("Sign"){ 25 | // if (params.BUILD_CONFIG == 'release') { 26 | // signAndroidApks ( 27 | // keyStoreId: keyStoreId, 28 | // keyAlias: keyAlias, 29 | // apksToSign: "**/*-unsigned.apk", 30 | // uncomment the following line to output the signed APK to a separate directory as described above 31 | // signedApkMapping: [ $class: UnsignedApkBuilderDirMapping ], 32 | // uncomment the following line to output the signed APK as a sibling of the unsigned APK, as described above, or just omit signedApkMapping 33 | // you can override these within the script if necessary 34 | // androidHome: '/usr/local/Cellar/android-sdk' 35 | // ) 36 | // } else { 37 | // println('Debug Build - Using default developer signing key') 38 | // } 39 | // } 40 | 41 | stage('Kryptowire') { 42 | //using a try-catch block so the pipeline script won't fail if the krypowire plugin is not installed 43 | try { 44 | if (params.BUILD_CONFIG == 'release') { 45 | kwSubmit filePath: "app/build/outputs/apk/release/app-release.apk", platform: 'android' 46 | } else { 47 | kwSubmit filePath: "app/build/outputs/apk/debug/app-debug.apk", platform: 'android' 48 | } 49 | } catch(Error e) { 50 | e.printStackTrace() 51 | } 52 | } 53 | 54 | 55 | 56 | stage("Archive"){ 57 | if (params.BUILD_CONFIG == 'release') { 58 | archiveArtifacts artifacts: 'app/build/outputs/apk/**/app-release.apk', excludes: 'app/build/outputs/apk/*-unaligned.apk' 59 | } else { 60 | archiveArtifacts artifacts: 'app/build/outputs/apk/**/app-debug.apk', excludes: 'app/build/outputs/apk/*-unaligned.apk' 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_push.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 19 | 20 | 31 | 32 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_authentication.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 18 |