add crash reporting

reports crashes with acra to an instance of acralyzer.
a new setting controls the usage of it.
required some workarounds for the application class.
include the default proguard file, includes some other proguard rules
acra requires (and is cleaner anyway).

closes #390
refactor-toolbar
Floens 8 years ago
parent fef2187ee0
commit f022269b6f
  1. 7
      Clover/app/build.gradle
  2. 13
      Clover/app/proguard.cfg
  3. 11
      Clover/app/src/debug/java/org/floens/chan/ChanApplication.java
  4. 13
      Clover/app/src/main/java/org/floens/chan/Chan.java
  5. 4
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  6. 16
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  7. 18
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java
  8. 4
      Clover/app/src/main/res/values/strings.xml
  9. 121
      Clover/app/src/release/java/org/floens/chan/ChanApplication.java

@ -78,6 +78,7 @@ android {
resValue "string", "app_name", "Clover"
resValue "string", "app_flavor_name", ""
buildConfigField "String", "UPDATE_API_ENDPOINT", "\"https://floens.github.io/Clover/api/update\""
buildConfigField "String", "CRASH_REPORT_ENDPOINT", "\"https://acra.floens.org/clover/report\""
}
dev {
@ -86,6 +87,7 @@ android {
resValue "string", "app_name", "Clover dev"
resValue "string", "app_flavor_name", ""
buildConfigField "String", "UPDATE_API_ENDPOINT", "\"\""
buildConfigField "String", "CRASH_REPORT_ENDPOINT", "\"\""
}
fdroid {
@ -94,6 +96,7 @@ android {
resValue "string", "app_name", "Clover"
resValue "string", "app_flavor_name", "F-Droid"
buildConfigField "String", "UPDATE_API_ENDPOINT", "\"https://floens.github.io/Clover/api/update\""
buildConfigField "String", "CRASH_REPORT_ENDPOINT", "\"https://acra.floens.org/clover/report\""
}
}
@ -103,7 +106,7 @@ android {
signingConfig signingConfigs.release
}
minifyEnabled true
proguardFiles 'proguard.cfg'
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'
}
debug {
@ -141,4 +144,6 @@ dependencies {
implementation 'com.google.code.gson:gson:2.8.1'
implementation 'me.xdrop:fuzzywuzzy:1.1.9'
implementation 'org.codejargon.feather:feather:1.0'
releaseImplementation 'ch.acra:acra-http:5.0.1'
}

@ -110,4 +110,15 @@
-keep public class android.support.v7.widget.RecyclerView
-keep public class android.support.v4.widget.SlidingPaneLayout
-dontwarn dagger.internal.**
# Keep Feather inject working.
-keepclassmembers,allowobfuscation class * {
@javax.inject.* *;
<init>();
}
# ACRA stuff
# ACRA loads Plugins using reflection, so we need to keep all Plugin classes
-keep class * extends @android.support.annotation.Keep org.acra.** {*;}
# ACRA uses enum fields in annotations, so we have to keep those
-keep enum org.acra.** {*;}

@ -17,5 +17,16 @@
*/
package org.floens.chan;
/**
* The ChanApplication belonging to the debug configuration.
*
* It does not have acra enabled, unlike the release version, and immediately calls initialize.
*/
public class ChanApplication extends Chan {
@Override
public void onCreate() {
super.onCreate();
initialize();
}
}

@ -20,6 +20,7 @@ package org.floens.chan;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
@ -41,6 +42,7 @@ import javax.inject.Inject;
import de.greenrobot.event.EventBus;
@SuppressLint("Registered") // extended by ChanApplication, which is registered in the manifest.
public class Chan extends Application implements UserAgentProvider, Application.ActivityLifecycleCallbacks {
private static final String TAG = "ChanApplication";
@ -55,6 +57,7 @@ public class Chan extends Application implements UserAgentProvider, Application.
@Inject
DatabaseManager databaseManager;
private Feather feather;
public Chan() {
@ -75,15 +78,17 @@ public class Chan extends Application implements UserAgentProvider, Application.
}
@Override
public void onCreate() {
super.onCreate();
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
AndroidUtils.init(this);
}
public void initialize() {
final long startTime = Time.startTiming();
registerActivityLifecycleCallbacks(this);
AndroidUtils.init(this);
userAgent = createUserAgent();
initializeGraph();

@ -155,6 +155,8 @@ public class ChanSettings {
public static final LongSetting updateCheckTime;
public static final LongSetting updateCheckInterval;
public static final BooleanSetting crashReporting;
static {
SharedPreferences p = AndroidUtils.getPreferences();
@ -238,6 +240,8 @@ public class ChanSettings {
updateCheckTime = new LongSetting(p, "update_check_time", 0L);
updateCheckInterval = new LongSetting(p, "update_check_interval", UpdateManager.DEFAULT_UPDATE_CHECK_INTERVAL_MS);
crashReporting = new BooleanSetting(p, "preference_crash_reporting", true);
// Old (but possibly still in some users phone)
// preference_board_view_mode default "list"
// preference_board_editor_filler default false

@ -29,6 +29,7 @@ import org.floens.chan.R;
import org.floens.chan.core.presenter.SettingsPresenter;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.settings.BooleanSettingView;
import org.floens.chan.ui.settings.LinkSettingView;
import org.floens.chan.ui.settings.SettingView;
import org.floens.chan.ui.settings.SettingsController;
@ -49,6 +50,7 @@ public class MainSettingsController extends SettingsController implements Settin
private SettingView developerView;
private LinkSettingView sitesSetting;
private LinkSettingView filtersSetting;
private SettingView crashReportSetting;
public MainSettingsController(Context context) {
super(context);
@ -106,6 +108,15 @@ public class MainSettingsController extends SettingsController implements Settin
R.string.setting_watch_summary_enabled : R.string.setting_watch_summary_disabled);
}
@Override
public void onPreferenceChange(SettingView item) {
super.onPreferenceChange(item);
if (item == crashReportSetting) {
Toast.makeText(context, R.string.settings_crash_reporting_toggle_notice,
Toast.LENGTH_LONG).show();
}
}
private void populatePreferences() {
// General group
{
@ -153,6 +164,11 @@ public class MainSettingsController extends SettingsController implements Settin
setupUpdateSetting(about);
crashReportSetting = about.add(new BooleanSettingView(this,
ChanSettings.crashReporting,
R.string.settings_crash_reporting,
R.string.settings_crash_reporting_description));
setupExtraAboutSettings(about, version);
about.add(new LinkSettingView(this,

@ -75,14 +75,16 @@ public class AndroidUtils {
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
public static void init(Application application) {
AndroidUtils.application = application;
if (AndroidUtils.application == null) {
AndroidUtils.application = application;
ROBOTO_MEDIUM = getTypeface("Roboto-Medium.ttf");
ROBOTO_MEDIUM_ITALIC = getTypeface("Roboto-MediumItalic.ttf");
ROBOTO_CONDENSED_REGULAR = getTypeface("RobotoCondensed-Regular.ttf");
ROBOTO_MEDIUM = getTypeface("Roboto-Medium.ttf");
ROBOTO_MEDIUM_ITALIC = getTypeface("Roboto-MediumItalic.ttf");
ROBOTO_CONDENSED_REGULAR = getTypeface("RobotoCondensed-Regular.ttf");
connectivityManager = (ConnectivityManager)
application.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager = (ConnectivityManager)
application.getSystemService(Context.CONNECTIVITY_SERVICE);
}
}
public static Resources getRes() {
@ -101,6 +103,10 @@ public class AndroidUtils {
return PreferenceManager.getDefaultSharedPreferences(application);
}
public static SharedPreferences getPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
public static SharedPreferences getPreferences(String name) {
return application.getSharedPreferences(name, Context.MODE_PRIVATE);
}

@ -421,6 +421,10 @@ Re-enable this permission in the app settings if you permanently disabled it."</
<!-- Main About group -->
<string name="settings_group_about">About</string>
<string name="settings_update_check">Check for updates</string>
<string name="settings_crash_reporting">Report crashes</string>
<string name="settings_crash_reporting_description">Crash reporting creates reports of errors in Clover.
Crash reports do not collect any personally identifiable information.</string>
<string name="settings_crash_reporting_toggle_notice">Setting will be applied on next app start.</string>
<string name="settings_about_license">Released under the GNU GPLv3 license</string>
<string name="settings_about_license_description">Tap to see license</string>
<string name="settings_about_licenses">Open Source Licenses</string>

@ -0,0 +1,121 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan;
import android.content.Context;
import org.acra.ACRA;
import org.acra.annotation.AcraCore;
import org.acra.annotation.AcraHttpSender;
import org.acra.data.StringFormat;
import org.acra.sender.HttpSender;
import org.floens.chan.core.settings.ChanSettings;
import static org.acra.ReportField.ANDROID_VERSION;
import static org.acra.ReportField.APP_VERSION_CODE;
import static org.acra.ReportField.APP_VERSION_NAME;
import static org.acra.ReportField.AVAILABLE_MEM_SIZE;
import static org.acra.ReportField.BRAND;
import static org.acra.ReportField.BUILD;
import static org.acra.ReportField.BUILD_CONFIG;
import static org.acra.ReportField.LOGCAT;
import static org.acra.ReportField.MEDIA_CODEC_LIST;
import static org.acra.ReportField.PACKAGE_NAME;
import static org.acra.ReportField.PHONE_MODEL;
import static org.acra.ReportField.PRODUCT;
import static org.acra.ReportField.REPORT_ID;
import static org.acra.ReportField.STACK_TRACE;
import static org.acra.ReportField.TOTAL_MEM_SIZE;
import static org.acra.ReportField.USER_APP_START_DATE;
import static org.acra.ReportField.USER_CRASH_DATE;
/**
* The ChanApplication belonging to the release configuration.
* <p>
* It has acra enabled. Acra unfortunately believes it needs to have annotations on our
* application class, which I find really intrusive. We already had ChanApplication pointing to
* Chan, so we now have a debug and release variant of ChanApplication. The real initialization
* is done with the {@link Chan#initialize()} method, which does not get called from acra
* processes.
*/
@AcraCore(
sharedPreferencesName = "acra_preferences",
alsoReportToAndroidFramework = true,
buildConfigClass = BuildConfig.class,
reportFormat = StringFormat.JSON,
reportContent = {
// Required
REPORT_ID,
// What app version
APP_VERSION_CODE,
APP_VERSION_NAME,
PACKAGE_NAME,
BUILD_CONFIG,
// What phone
PHONE_MODEL,
BRAND,
PRODUCT,
// What Android version
ANDROID_VERSION,
BUILD,
// Memory details
TOTAL_MEM_SIZE,
AVAILABLE_MEM_SIZE,
// Useful for webm debugging
MEDIA_CODEC_LIST,
// The error
STACK_TRACE,
LOGCAT,
USER_APP_START_DATE,
USER_CRASH_DATE
}
)
@AcraHttpSender(
httpMethod = HttpSender.Method.PUT,
uri = BuildConfig.CRASH_REPORT_ENDPOINT
)
public class ChanApplication extends Chan {
@Override
public void onCreate() {
super.onCreate();
// Do not initialize again if running from the crash reporting process.
if (!ACRA.isACRASenderServiceProcess()) {
initialize();
}
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
if (enableAcra()) {
ACRA.init(this);
}
}
private boolean enableAcra() {
return !BuildConfig.CRASH_REPORT_ENDPOINT.isEmpty() && ChanSettings.crashReporting.get();
}
}
Loading…
Cancel
Save