diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 4d30d115d..6da7283a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -158,6 +158,9 @@ public final class Constants { public static final String KEY_SIGNATURES_TABLE_INITIALIZED = "key_signatures_table_initialized"; + public static final String KEY_ANALYTICS_ASKED_POLITELY = "analytics_asked"; + public static final String KEY_ANALYTICS_CONSENT = "analytics_consent"; + public static final class Theme { public static final String LIGHT = "light"; public static final String DARK = "dark"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/TrackingManager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/TrackingManager.java index 1be0e19da..dc42d0237 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/TrackingManager.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/TrackingManager.java @@ -6,34 +6,31 @@ import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.content.Context; import android.os.Bundle; +import android.support.annotation.NonNull; import org.piwik.sdk.Piwik; import org.piwik.sdk.Tracker; import org.piwik.sdk.TrackerConfig; import org.piwik.sdk.extra.DownloadTracker.Extra.ApkChecksum; import org.piwik.sdk.extra.TrackHelper; +import org.sufficientlysecure.keychain.util.Preferences; public class TrackingManager { private Tracker piwikTracker; public static TrackingManager getInstance(Context context) { - TrackerConfig trackerConfig = new TrackerConfig("https://mugenguild.com/piwik/", 1, "OpenKeychain"); - Tracker tracker = Piwik.getInstance(context).newTracker(trackerConfig); - tracker.setDispatchInterval(30000); - - return new TrackingManager(tracker); + return new TrackingManager(context); } - private TrackingManager(Tracker piwikTracker) { - this.piwikTracker = piwikTracker; + private TrackingManager(Context context) { + refreshSettings(context); } public void initialize(Application application) { - if (piwikTracker == null) { - return; + if (piwikTracker != null) { + TrackHelper.track().download().identifier(new ApkChecksum(application)).with(piwikTracker); } - TrackHelper.track().download().identifier(new ApkChecksum(application)).with(piwikTracker); application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override @@ -47,6 +44,9 @@ public class TrackingManager { @Override public void onActivityResumed(Activity activity) { + if (piwikTracker == null) { + return; + } TrackHelper.track().screen(activity.getClass().getSimpleName()).with(piwikTracker); } @@ -99,4 +99,20 @@ public class TrackingManager { .piece(currentCallingPackage.replace(".", "/")) .with(piwikTracker); } + + public synchronized void refreshSettings(Context context) { + boolean analyticsHasConsent = Preferences.getPreferences(context).isAnalyticsHasConsent(); + boolean analyticsEnabled = piwikTracker != null; + if (analyticsHasConsent != analyticsEnabled) { + if (analyticsHasConsent) { + TrackerConfig trackerConfig = new TrackerConfig("https://piwik.openkeychain.org/", 1, "OpenKeychain"); + piwikTracker = Piwik.getInstance(context).newTracker(trackerConfig); + piwikTracker.setDispatchInterval(60000); + piwikTracker.setOptOut(false); + } else { + piwikTracker.setOptOut(true); + piwikTracker = null; + } + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 82a93632e..3ed742297 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -20,12 +20,17 @@ package org.sufficientlysecure.keychain.ui; import java.io.IOException; import java.util.List; +import java.util.concurrent.TimeUnit; import android.animation.ObjectAnimator; import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; import android.arch.lifecycle.LiveData; import android.arch.lifecycle.ViewModelProviders; +import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager.NameNotFoundException; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.WorkerThread; @@ -51,9 +56,12 @@ import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener; import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemLongClickListener; import eu.davidea.flexibleadapter.SelectableAdapter.Mode; +import org.sufficientlysecure.keychain.BuildConfig; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.KeychainApplication; import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.TrackingManager; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.KeyRepository; @@ -259,6 +267,8 @@ public class KeyListFragment extends RecyclerFragment> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems); liveData.observe(this, this::onLoadKeyItems); + + maybeAskForAnalytics(); } @WorkerThread @@ -267,6 +277,45 @@ public class KeyListFragment extends RecyclerFragment threeDaysAgo; + if (installedLessThanThreeDaysAgo) { + return; + } + } catch (NameNotFoundException e) { + return; + } + + TrackingManager trackingManager = ((KeychainApplication) requireActivity().getApplication()).getTrackingManager(); + AlertDialog show = new Builder(context) + .setMessage(R.string.dialog_analytics_text) + .setPositiveButton(R.string.button_analytics_yes, (dialog, which) -> { + preferences.setAnalyticsAskedPolitely(); + preferences.setAnalyticsGotUserConsent(true); + trackingManager.refreshSettings(context); + }) + .setNegativeButton(R.string.button_analytics_no, (dialog, which) -> { + preferences.setAnalyticsAskedPolitely(); + preferences.setAnalyticsGotUserConsent(false); + trackingManager.refreshSettings(context); + }) + .show(); + show.setCanceledOnTouchOutside(false); + } + private void onLoadKeyItems(List flexibleKeyItems) { FlexibleAdapter adapter = getAdapter(); if (adapter == null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index f12943f14..37042fdb9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -37,6 +37,7 @@ import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.preference.SwitchPreference; @@ -50,6 +51,7 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Constants.Pref; import org.sufficientlysecure.keychain.KeychainApplication; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.AppCompatPreferenceActivity; @@ -584,6 +586,14 @@ public class SettingsActivity extends AppCompatPreferenceActivity { }); } + @Override + public void onPause() { + super.onPause(); + + Activity activity = getActivity(); + ((KeychainApplication) activity.getApplication()).getTrackingManager().refreshSettings(activity); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 38773c116..f73baf6c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -353,6 +353,22 @@ public class Preferences { mSharedPreferences.edit().putBoolean(Pref.SYNC_IS_SCHEDULED, isScheduled).apply(); } + public boolean isAnalyticsAskedPolitely() { + return mSharedPreferences.getBoolean(Pref.KEY_ANALYTICS_ASKED_POLITELY, false); + } + + public void setAnalyticsAskedPolitely() { + mSharedPreferences.edit().putBoolean(Pref.KEY_ANALYTICS_ASKED_POLITELY, true).apply(); + } + + public boolean isAnalyticsHasConsent() { + return mSharedPreferences.getBoolean(Pref.KEY_ANALYTICS_CONSENT, false); + } + + public void setAnalyticsGotUserConsent(boolean hasUserConsent) { + mSharedPreferences.edit().putBoolean(Pref.KEY_ANALYTICS_CONSENT, hasUserConsent).apply(); + } + @AutoValue public static abstract class CloudSearchPrefs implements Parcelable { public abstract boolean isKeyserverEnabled(); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 5a7d2ac92..6349870dc 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -236,6 +236,9 @@ "Contact keybase.io for key proofs and show them every time a key is displayed" "(The icons and many screens are not yet adjusted accordingly for the dark theme)" + Allow anonymous usage statistics + If enabled, sends anonymous usage statistics to help improve the app + "Enable Tor" "Requires Orbot to be installed" @@ -2045,4 +2048,7 @@ Anonymous # + Allow OpenKeychain to collect anonymous usage statistics to help improve the app? + Yes, I want to help! + No, thanks diff --git a/OpenKeychain/src/main/res/xml/experimental_preferences.xml b/OpenKeychain/src/main/res/xml/experimental_preferences.xml index e557f06e6..fd21a546c 100644 --- a/OpenKeychain/src/main/res/xml/experimental_preferences.xml +++ b/OpenKeychain/src/main/res/xml/experimental_preferences.xml @@ -5,6 +5,13 @@ android:summary="@string/label_experimental_settings_desc_summary" android:title="@string/label_experimental_settings_desc_title" /> + +