From fe364c20f40041f5d3f2a4d5e99a7a6af2a16519 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Oct 2018 14:11:19 +0300 Subject: [PATCH] Added initial consent dialog --- PRIVACY.md | 22 +++--- README.md | 7 +- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 1 + app/src/main/assets/PRIVACY.md | 76 +++++++++++++++++++ app/src/main/assets/apache_libraries.html | 3 + .../mthmmy/activities/LoginActivity.java | 31 ++++---- .../gr/thmmy/mthmmy/base/BaseActivity.java | 75 +++++++++++++++++- .../gr/thmmy/mthmmy/base/BaseApplication.java | 4 + .../gr/thmmy/mthmmy/utils/LaunchType.java | 40 ++++++++++ app/src/main/res/values-v21/styles.xml | 27 +------ app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 26 +++++-- 13 files changed, 252 insertions(+), 63 deletions(-) create mode 100644 app/src/main/assets/PRIVACY.md create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java diff --git a/PRIVACY.md b/PRIVACY.md index 7b560b40..8e69038c 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -1,6 +1,6 @@ # Privacy Policy -*Effective date: 7/10/2018* +*Effective date: 13/10/2018* Thmmy No Life ("us", "we", or "our") developed the mTHMMY mobile app (the "App") as an open source application. It is provided by us at no cost and is intended for use as is. @@ -16,7 +16,7 @@ Google Ireland Limited ("Google"), with offices at Gordon House, Barrow Street, The majority of Firebase services run on global Google infrastructure. They could process data at any of the Google Cloud Platform locations or Google data center locations, within or outside the European Union (EU). -The Commission Decision (EU) 2016/1250 of 12.07.2016 allows the transfer of data from an EU controller or processor of orders to organizations in the US that have committed themselves to adhere to the framework principles of the EU-US Privacy Shield (https://www.privacyshield.gov), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. +The Commission Decision (EU) 2016/1250 of 12.07.2016 allows the transfer of data from an EU controller or processor of orders to organizations in the US that have committed themselves to adhere to the framework principles of the EU-US Privacy Shield (), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. ### General Information @@ -37,22 +37,22 @@ The use of each Firebase service is explained below: ### Firebase Crashlytics * **Purpose**: This service automatically collects and delivers analyses of errors and system crashes in real time and displays them in the Firebase Console. This helps us maintain the App and improve its stability. -* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: https://try.crashlytics.com/security/ +* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: * **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable it from the Settings inside the App. * **Retention**: Crash traces and their associated identifiers are kept for 90 days. ### Google Analytics for Firebase * **Purpose**: This service provides analytics and attribution information for statistical purposes. The precise information collected can vary by the device and environment. -* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: https://support.google.com/firebase/answer/6318039 +* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: * **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable (and clear all collected data) from the Settings inside the App. * **Retention**: ID-associated data are retained for 60 days. Aggregate reporting and campaign data are retained without automatic expiration. You can find further information on the data use by Google through Firebase following the links below: -https://firebase.google.com/terms/ -https://firebase.google.com/terms/data-processing-terms -https://firebase.google.com/support/privacy/ -https://firebase.google.com/support/privacy/manage-iids + + + + ## Other data @@ -61,7 +61,7 @@ https://firebase.google.com/support/privacy/manage-iids ## About thmmy.gr -We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at https://www.thmmy.gr/smf/index.php?topic=52522. +We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at . ## Third-Party Links @@ -69,8 +69,8 @@ mTHMMY may contain links to third-party websites. Any access to and use of such ## Policy Updates -We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at https://github.com/ThmmyNoLife/mTHMMY/blob/develop/PRIVACY.md. +We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at . ## Contact Us -If you have any question about our Privacy Policy, please contact us at thmmynolife@gmail.com. +If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). diff --git a/README.md b/README.md index 4118864b..529f01a5 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ [![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=19) [![Discord Channel](https://img.shields.io/badge/discord-public@mTHMMY-738bd7.svg?style=flat)][discord-server] +![alt text](app\src\main\res\mipmap-xhdpi\ic_launcher.png "mTHMMY") -mTHMMY is a mobile app for the [thmmy.gr](https://www.thmmy.gr) community. +A mobile app for [thmmy.gr](https://www.thmmy.gr). ## Requirements @@ -20,6 +21,10 @@ The latest release version is available on Google Play: Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md) for details. +## Privacy Policy + +Our Privacy Policy can be found [here](/PRIVACY.md). + ## Contact Do not hesitate to contact us for any matter, either by sending an email to [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com), or by joining our [Discord server][discord-server]. diff --git a/app/build.gradle b/app/build.gradle index 81b88eb7..79a71684 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ dependencies { implementation 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1'//TODO: deprecated! implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' implementation 'com.jakewharton.timber:timber:4.7.0' + implementation "ru.noties:markwon:2.0.0" implementation 'net.gotev:uploadservice:3.4.2' implementation 'net.gotev:uploadservice-okhttp:3.4.2' implementation 'android.arch.lifecycle:extensions:1.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 245e6ada..19f47c62 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ + ), including the additional principles, by way of self-certification with the US Department of Commerce. Google is subject to these principles through self-certification with the U.S. Department of Commerce. + +### General Information + +* The Firebase services that we use collect and further process anonymized information, data with no personally identifiable information which can be used to trace its source so that the people whom it describes can remain anonymous. These data are not subject to the same treatment as are personal data, particularly with regards to any desire you might have for accessing it, rectifying it or erasing it (Article 11, GDPR). +* Firebase uses the Instance ID of your mobile device to identify individual installations of this mobile app. Since each Instance ID is unique to a particular application and device, they give Firebase a way to refer to specific instances of the App. +* Your IP address transmitted by the App in the context of Firebase will not be merged with other collected data. +* Legal basis for the use of Firebase is Article 6 Par. 1 S. 1 letter (a) or (f), GDPR. + +The use of each Firebase service is explained below: + +### Firebase Cloud Messaging + +* **Purpose**: This service is essential for the funcionality of the App. It uses anonymous push notification tokens in order to determine which devices to deliver the appropriate messages to. +* **Data collected**: Instance IDs. +* **Consent**: You will be prompted to agree to the use of this service when you open the App for the first time. +* **Retention**: Firebase retains Instance IDs until we make an API call for deletion. After the call, data are removed from live and backup systems within 180 days. + +### Firebase Crashlytics + +* **Purpose**: This service automatically collects and delivers analyses of errors and system crashes in real time and displays them in the Firebase Console. This helps us maintain the App and improve its stability. +* **Data collected**: Instance IDs and crash reports with information about register codes and your device, e.g. type of device and version of operating system. For more information: +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable it from the Settings inside the App. +* **Retention**: Crash traces and their associated identifiers are kept for 90 days. + +### Google Analytics for Firebase + +* **Purpose**: This service provides analytics and attribution information for statistical purposes. The precise information collected can vary by the device and environment. +* **Data collected**: Instance IDs, Android IDs, Analytics App Instance IDs and custom events created by us. For more information: +* **Consent**: You will be prompted to choose if you want this service enabled when you open the App for the first time. After that, you can enable or disable (and clear all collected data) from the Settings inside the App. +* **Retention**: ID-associated data are retained for 60 days. Aggregate reporting and campaign data are retained without automatic expiration. + +You can find further information on the data use by Google through Firebase following the links below: + + + + + +## Other data + +* When downloading the mobile app, the necessary information is transferred to the App Store (Google Play), i.e. in particular the name, e-mail address and customer number of your customer account, time of download, payment information and the individual device identification number. We have no influence on this data collection and shall not be responsible for it. We only process the data if it is necessary for downloading the mobile app to your mobile device. +* The App provides functionality to login to thmmy.gr through an encrypted connection. This process generates session cookies that are stored on your device. Those cookies contain the same information as those that would be generated if you logged in using a web browser and we have no influence on them. Any other personal information that the App collects from you from thmmy.gr is only stored locally and never transmitted. You can delete all the data related to thmmy.gr anytime you wish, by logging out or clearing the App's data from your device's Settings. + +## About thmmy.gr + +We have neither influence, nor responsibility on anything you read, write, download or upload by interacting with thmmy.gr through the App. For more information you can also read the Terms of Service of thmmy.gr at . + +## Third-Party Links + +mTHMMY may contain links to third-party websites. Any access to and use of such linked websites is not governed by this Policy, but instead is governed by the privacy policies of those third party websites. We are not responsible for the information practices of such third party websites. + +## Policy Updates + +We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at . + +## Contact Us + +If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html index c739366e..004d8c96 100644 --- a/app/src/main/assets/apache_libraries.html +++ b/app/src/main/assets/apache_libraries.html @@ -65,6 +65,9 @@
  • Android Upload Service v3.4.2 (Copyright ©2013-2018 Aleksandar Gotev)
  • +
  • +
    Markwon v2.0.0 (Copyright ©2017 Dimitry Ivanov)
    +
  • diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java index 60b7d7aa..add3abaf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -3,10 +3,8 @@ package gr.thmmy.mthmmy.activities; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; -import android.support.annotation.NonNull; import android.support.v7.preference.PreferenceManager; import android.support.v7.widget.AppCompatButton; -import android.view.ActionMode; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -57,25 +55,22 @@ public class LoginActivity extends BaseActivity { AppCompatButton btnGuest = findViewById(R.id.btnContinueAsGuest); //Login button Click Event - btnLogin.setOnClickListener(new View.OnClickListener() { + btnLogin.setOnClickListener(view -> { + Timber.d("Login"); - public void onClick(View view) { - Timber.d("Login"); + //Get username and password strings + username = inputUsername.getText().toString().trim(); + password = inputPassword.getText().toString().trim(); - //Get username and password strings - username = inputUsername.getText().toString().trim(); - password = inputPassword.getText().toString().trim(); - - //Check for empty data in the form - if (!validate()) { - onLoginFailed(); - return; - } - - //Login user - loginTask = new LoginTask(); - loginTask.execute(username, password); + //Check for empty data in the form + if (!validate()) { + onLoginFailed(); + return; } + + //Login user + loginTask = new LoginTask(); + loginTask.execute(username, password); }); //Guest Button Action diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index d182adf7..b0d1c98e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -15,6 +15,7 @@ import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetDialog; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; +import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.preference.PreferenceManager; import android.support.v7.widget.Toolbar; @@ -36,7 +37,10 @@ import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import gr.thmmy.mthmmy.R; @@ -53,8 +57,12 @@ import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.FileUtils; +import gr.thmmy.mthmmy.utils.LaunchType; import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import okhttp3.OkHttpClient; +import ru.noties.markwon.LinkResolverDef; +import ru.noties.markwon.Markwon; +import ru.noties.markwon.SpannableConfiguration; import timber.log.Timber; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -67,8 +75,10 @@ import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_ import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS; import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; +import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.FIRST_LAUNCH_EVER; +import static gr.thmmy.mthmmy.utils.LaunchType.LAUNCH_TYPE.INDETERMINATE; -public abstract class BaseActivity extends AppCompatActivity { +public abstract class BaseActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener{ // Client & Cookies protected static OkHttpClient client; @@ -116,6 +126,8 @@ public abstract class BaseActivity extends AppCompatActivity { protected void onResume() { super.onResume(); updateDrawer(); + if(LaunchType.getLaunchType()==FIRST_LAUNCH_EVER||LaunchType.getLaunchType()== INDETERMINATE) + showUserConsentDialog(); } @Override @@ -714,6 +726,67 @@ public abstract class BaseActivity extends AppCompatActivity { dialog.show(); } + //----------------------------PRIVACY POLICY------------------ + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(getString(R.string.pref_pp_accepted_key))) + if(!sharedPreferences.getBoolean(key, false)) + showUserConsentDialog(); + } + + private void showUserConsentDialog(){ + AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); + builder.setTitle("User Agreement"); + builder.setMessage(R.string.user_agreement_dialog_text); + builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> FirebaseMessaging.getInstance().setAutoInitEnabled(true)); + builder.setNeutralButton("Privacy Policy", (dialog, which) -> {/*Will be overridden below*/}); + builder.setCancelable(false); + AlertDialog alertDialog = builder.create(); + alertDialog.setOnShowListener(dialogInterface -> { + Button button = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL); + button.setOnClickListener(view -> showPrivacyPolicyDialog()); + }); // Overridden like this so it won't be dismissed when user touches this button + alertDialog.show(); + } + + private void showPrivacyPolicyDialog() { + TextView privacyPolicyTextView = new TextView(this); + privacyPolicyTextView.setPadding(30,20,30,20); + privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text)); + SpannableConfiguration configuration = SpannableConfiguration.builder(this).linkResolver(new LinkResolverDef()).build(); + StringBuilder stringBuilder = new StringBuilder(); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(getAssets().open("PRIVACY.md"))); + String line; + + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + stringBuilder.append("\n"); + } + Markwon.setMarkdown(privacyPolicyTextView, configuration, stringBuilder.toString()); + AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); + builder.setView(privacyPolicyTextView); + builder.setPositiveButton("Close", (dialogInterface, i) -> dialogInterface.dismiss()); + builder.show(); + } catch (IOException e) { + Timber.e(e, "Error reading Privacy Policy from assets."); + } catch (Exception e) { + Timber.e(e, "Error in Privacy Policy dialog."); + } finally { + try { + if(reader!=null) + reader.close(); + } catch (IOException e) { + Timber.e(e, "Error in Privacy Policy dialog (closing reader)."); + } + } + } + + + //----------------------------------MISC---------------------- protected void setMainActivity(MainActivity mainActivity) { this.mainActivity = mainActivity; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java index 0f74807d..b2a930ee 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -165,6 +165,10 @@ public class BaseApplication extends Application { } //Getters + public Context getContext() { + return getApplicationContext(); + } + public OkHttpClient getClient() { return client; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java b/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java new file mode 100644 index 00000000..29411b55 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java @@ -0,0 +1,40 @@ +package gr.thmmy.mthmmy.utils; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import gr.thmmy.mthmmy.BuildConfig; +import gr.thmmy.mthmmy.base.BaseApplication; + +public class LaunchType { + public enum LAUNCH_TYPE { + FIRST_LAUNCH_EVER, FIRST_LAUNCH_AFTER_UPDATE, NORMAL_LAUNCH, INDETERMINATE + } + + private static final String PREF_VERSION_CODE_KEY = "VERSION_CODE"; + + public static LAUNCH_TYPE getLaunchType() { + final int notThere = -1; + //Gets current version code + int currentVersionCode = BuildConfig.VERSION_CODE; + //Gets saved version code + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(BaseApplication.getInstance().getContext()); + int savedVersionCode = prefs.getInt(PREF_VERSION_CODE_KEY, notThere); + //Checks for first run or upgrade + if (currentVersionCode == savedVersionCode) { + //This is just a normal run + return LAUNCH_TYPE.NORMAL_LAUNCH; + } else if (savedVersionCode == notThere) { + //Updates the shared preferences with the current version code + prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); + return LAUNCH_TYPE.FIRST_LAUNCH_EVER; + } else if (currentVersionCode > savedVersionCode) { + //Updates the shared preferences with the current version code + prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); + return LAUNCH_TYPE.FIRST_LAUNCH_AFTER_UPDATE; + } + //Probably shared preferences were manually changed by the user + return LAUNCH_TYPE.INDETERMINATE; + } +} + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index e16ea522..7011b5f0 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -1,33 +1,10 @@ - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c133b80..09711010 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,6 +14,8 @@ Info OK Cancel + pref_pp_accepted + "To use mTHMMY you have to agree to our Privacy Policy by choosing one of the buttons below. Choose \"Yes, I want to help\", if you consent to the collection of anonymized data that will help us improve the app. Otherwise, choose \"Nope, leave me alone\". You can change your preferences any time through the app's Settings. thmmy.gr diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 90595469..9d79d36d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,6 @@ - - - - + @@ -46,14 +50,18 @@ @color/primary_text - - + + + +