diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 5d54ab2e1..8ea033382 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -79,11 +79,8 @@
android:windowSoftInputMode="adjustResize|stateHidden" />
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
index 80dbbeb4f..b1168d848 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
@@ -33,9 +33,6 @@ import org.briarproject.briar.BriarCoreModule;
import org.briarproject.briar.android.attachment.AttachmentModule;
import org.briarproject.briar.android.conversation.glide.BriarModelLoader;
import org.briarproject.briar.android.login.SignInReminderReceiver;
-import org.briarproject.briar.android.reporting.CrashFragment;
-import org.briarproject.briar.android.reporting.CrashReportActivity;
-import org.briarproject.briar.android.reporting.ReportFormFragment;
import org.briarproject.briar.android.view.EmojiTextInputView;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog;
@@ -175,10 +172,6 @@ public interface AndroidComponent
void inject(BriarService briarService);
- void inject(CrashReportActivity crashReportActivity);
- void inject(ReportFormFragment reportFormFragment);
- void inject(CrashFragment crashFragment);
-
void inject(NotificationCleanupService notificationCleanupService);
void inject(EmojiTextInputView textInputView);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
index bf07eda7b..09946b3a7 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
@@ -23,7 +23,5 @@ public interface BriarApplication extends BrambleApplication {
SharedPreferences getDefaultSharedPreferences();
- void triggerFeedback();
-
boolean isRunningInBackground();
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java
index 9cd8332ef..64022ec6f 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplicationImpl.java
@@ -151,11 +151,6 @@ public class BriarApplicationImpl extends Application
return prefs;
}
- @Override
- public void triggerFeedback() {
- exceptionHandler.feedback();
- }
-
@Override
public boolean isRunningInBackground() {
RunningAppProcessInfo info = new RunningAppProcessInfo();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
index e71e7d786..51e524319 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
@@ -66,6 +66,9 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberModule;
import org.briarproject.briar.android.privategroup.reveal.GroupRevealModule;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment;
+import org.briarproject.briar.android.reporting.CrashFragment;
+import org.briarproject.briar.android.reporting.CrashReportActivity;
+import org.briarproject.briar.android.reporting.ReportFormFragment;
import org.briarproject.briar.android.settings.SettingsActivity;
import org.briarproject.briar.android.settings.SettingsFragment;
import org.briarproject.briar.android.sharing.BlogInvitationActivity;
@@ -184,6 +187,8 @@ public interface ActivityComponent {
void inject(PendingContactListActivity activity);
+ void inject(CrashReportActivity crashReportActivity);
+
// Fragments
void inject(AuthorNameFragment fragment);
@@ -234,4 +239,8 @@ public interface ActivityComponent {
void inject(ImageFragment imageFragment);
+ void inject(ReportFormFragment reportFormFragment);
+
+ void inject(CrashFragment crashFragment);
+
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
index 8369634ef..f67f1fc91 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
@@ -18,7 +18,6 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.forum.ForumModule;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment;
-import org.briarproject.briar.android.reporting.CrashReportActivity;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.android.widget.TapSafeFrameLayout;
import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener;
@@ -50,7 +49,6 @@ import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
/**
* Warning: Some activities don't extend {@link BaseActivity}.
- * E.g. {@link CrashReportActivity}
*/
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -123,6 +121,7 @@ public abstract class BaseActivity extends AppCompatActivity
return new ActivityModule(this);
}
+ // TODO use a test module where this is used in tests
protected ForumModule getForumModule() {
return new ForumModule();
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java
index a4bd9c8f2..be708d73c 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeErrorFragment.java
@@ -10,13 +10,10 @@ import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
-import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment;
-
-import javax.inject.Inject;
+import org.briarproject.briar.android.util.UiUtils;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
@@ -41,9 +38,6 @@ public class ContactExchangeErrorFragment extends BaseFragment {
return f;
}
- @Inject
- AndroidExecutor androidExecutor;
-
@Override
public String getUniqueTag() {
return TAG;
@@ -88,10 +82,8 @@ public class ContactExchangeErrorFragment extends BaseFragment {
}
private void triggerFeedback() {
- BriarApplication app =
- (BriarApplication) requireContext().getApplicationContext();
+ UiUtils.triggerFeedback(requireContext());
finish();
- app.triggerFeedback();
}
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarExceptionHandler.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarExceptionHandler.java
index 8858d769c..3568bc8b4 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarExceptionHandler.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarExceptionHandler.java
@@ -1,19 +1,13 @@
package org.briarproject.briar.android.reporting;
import android.content.Context;
-import android.content.Intent;
import android.os.Process;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
-import org.briarproject.briar.android.util.UserFeedback;
import java.lang.Thread.UncaughtExceptionHandler;
-import androidx.fragment.app.FragmentActivity;
-
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME;
-import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_THROWABLE;
+import static org.briarproject.briar.android.util.UiUtils.startDevReportActivity;
@NotNullByDefault
public class BriarExceptionHandler implements UncaughtExceptionHandler {
@@ -29,22 +23,9 @@ public class BriarExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// activity runs in its own process, so we can kill the old one
- startDevReportActivity(CrashReportActivity.class, e);
+ startDevReportActivity(ctx, CrashReportActivity.class, e, appStartTime);
Process.killProcess(Process.myPid());
System.exit(10);
}
- public void feedback() {
- startDevReportActivity(FeedbackActivity.class, new UserFeedback());
- }
-
- private void startDevReportActivity(
- Class extends FragmentActivity> activity, Throwable e) {
- final Intent dialogIntent = new Intent(ctx, activity);
- dialogIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- dialogIntent.putExtra(EXTRA_THROWABLE, e);
- dialogIntent.putExtra(EXTRA_APP_START_TIME, appStartTime);
- ctx.startActivity(dialogIntent);
- }
-
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java
index cd0e6622d..3f3e3f349 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java
@@ -21,12 +21,14 @@ import android.os.Build;
import android.os.Environment;
import org.briarproject.bramble.api.Pair;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.BuildConfig;
import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.logging.BriefLogFormatter;
import org.briarproject.briar.android.reporting.ReportData.MultiReportInfo;
import org.briarproject.briar.android.reporting.ReportData.ReportItem;
+import org.briarproject.briar.android.reporting.ReportData.SingleReportInfo;
import java.io.File;
import java.io.PrintWriter;
@@ -40,6 +42,8 @@ import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
+import javax.annotation.concurrent.Immutable;
+
import androidx.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
@@ -56,6 +60,8 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
+@Immutable
+@NotNullByDefault
class BriarReportCollector {
private final Context ctx;
@@ -66,9 +72,11 @@ class BriarReportCollector {
public ReportData collectReportData(@Nullable Throwable t,
long appStartTime) {
- return new ReportData()
+ ReportData reportData = new ReportData()
.add(getBasicInfo(t))
- .add(getDeviceInfo())
+ .add(getDeviceInfo());
+ if (t != null) reportData.add(getStacktrace(t));
+ return reportData
.add(getTimeInfo(appStartTime))
.add(getMemory())
.add(getStorage())
@@ -91,27 +99,18 @@ class BriarReportCollector {
versionCode = "?";
}
MultiReportInfo basicInfo = new MultiReportInfo()
- .add("Package name", packageName)
- .add("Version name", versionName)
- .add("Version code", versionCode);
- // print stacktrace of Throwable if this is not feedback
- if (t != null) {
- final Writer sw = new StringWriter();
- final PrintWriter printWriter = new PrintWriter(sw);
- if (!isNullOrEmpty(t.getMessage())) {
- printWriter.println(t.getMessage());
- }
- t.printStackTrace(printWriter);
- basicInfo.add("stracktrace", sw.toString());
- }
+ .add("PackageName", packageName)
+ .add("VersionName", versionName)
+ .add("VersionCode", versionCode)
+ .add("isCrashReport", String.valueOf(t != null));
return new ReportItem("BasicInfo", R.string.dev_report_basic_info,
basicInfo, false);
}
private ReportItem getDeviceInfo() {
MultiReportInfo deviceInfo = new MultiReportInfo()
- .add("Android version", Build.VERSION.RELEASE)
- .add("Android SDK API", String.valueOf(SDK_INT))
+ .add("AndroidVersion", Build.VERSION.RELEASE)
+ .add("AndroidApi", String.valueOf(SDK_INT))
.add("Product", Build.PRODUCT)
.add("Model", Build.MODEL)
.add("Brand", Build.BRAND);
@@ -119,10 +118,24 @@ class BriarReportCollector {
deviceInfo);
}
+ private ReportItem getStacktrace(Throwable t) {
+ final Writer sw = new StringWriter();
+ final PrintWriter printWriter = new PrintWriter(sw);
+ if (!isNullOrEmpty(t.getMessage())) {
+ printWriter.println(t.getMessage());
+ }
+ t.printStackTrace(printWriter);
+ SingleReportInfo stacktrace = new SingleReportInfo(sw.toString());
+ return new ReportItem("Stacktrace", R.string.dev_report_stacktrace,
+ stacktrace);
+ }
+
private ReportItem getTimeInfo(long startTime) {
MultiReportInfo timeInfo = new MultiReportInfo()
- .add("App start time", formatTime(startTime))
- .add("Crash time", formatTime(System.currentTimeMillis()));
+ .add("ReportTime", formatTime(System.currentTimeMillis()));
+ if (startTime > -1) {
+ timeInfo.add("AppStartTime", formatTime(startTime));
+ }
return new ReportItem("DeviceInfo", R.string.dev_report_time_info,
timeInfo);
}
@@ -132,53 +145,59 @@ class BriarReportCollector {
}
private ReportItem getMemory() {
+ MultiReportInfo memInfo = new MultiReportInfo();
+
// System memory
ActivityManager am = getSystemService(ctx, ActivityManager.class);
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
requireNonNull(am).getMemoryInfo(mem);
- String systemMemory;
- systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, "
- + (mem.availMem / 1024 / 1204) + " MiB free, "
- + (mem.threshold / 1024 / 1024) + " MiB threshold";
+ String systemTotal = (mem.totalMem / 1024 / 1024) + " MiB";
+ String systemFree = (mem.availMem / 1024 / 1024) + " MiB";
+ String systemThreshold = (mem.threshold / 1024 / 1024) + " MiB";
+ memInfo.add("SystemMemoryTotal", systemTotal);
+ memInfo.add("SystemMemoryFree", systemFree);
+ memInfo.add("SystemMemoryThreshold", systemThreshold);
// Virtual machine memory
Runtime runtime = Runtime.getRuntime();
long heap = runtime.totalMemory();
long heapFree = runtime.freeMemory();
long heapMax = runtime.maxMemory();
- String vmMemory = (heap / 1024 / 1024) + " MiB allocated, "
- + (heapFree / 1024 / 1024) + " MiB free, "
- + (heapMax / 1024 / 1024) + " MiB maximum";
+ String vmMemoryAllocated = (heap / 1024 / 1024) + " MiB";
+ String vmMemoryFree = (heapFree / 1024 / 1024) + " MiB";
+ String vmMemoryMax = (heapMax / 1024 / 1024) + " MiB";
+ memInfo.add("VirtualMachineMemoryAllocated", vmMemoryAllocated);
+ memInfo.add("VirtualMachineMemoryFree", vmMemoryFree);
+ memInfo.add("VirtualMachineMemoryMaximum", vmMemoryMax);
- MultiReportInfo memInfo = new MultiReportInfo()
- .add("System memory", systemMemory)
- .add("Virtual machine memory", vmMemory);
return new ReportItem("Memory", R.string.dev_report_memory, memInfo);
}
private ReportItem getStorage() {
+ MultiReportInfo storageInfo = new MultiReportInfo();
+
// Internal storage
File root = Environment.getRootDirectory();
long rootTotal = root.getTotalSpace();
long rootFree = root.getFreeSpace();
- String internal = (rootTotal / 1024 / 1024) + " MiB total, "
- + (rootFree / 1024 / 1024) + " MiB free";
+ storageInfo.add("InternalStorageTotal",
+ (rootTotal / 1024 / 1024) + " MiB");
+ storageInfo.add("InternalStorageFree",
+ (rootFree / 1024 / 1024) + " MiB");
// External storage (SD card)
File sd = Environment.getExternalStorageDirectory();
long sdTotal = sd.getTotalSpace();
long sdFree = sd.getFreeSpace();
- String external = (sdTotal / 1024 / 1024) + " MiB total, "
- + (sdFree / 1024 / 1024) + " MiB free";
+ storageInfo.add("ExternalStorageTotal",
+ (sdTotal / 1024 / 1024) + " MiB");
+ storageInfo.add("ExternalStorageFree",
+ (sdFree / 1024 / 1024) + " MiB");
- MultiReportInfo storageInfo = new MultiReportInfo()
- .add("Internal storage", internal)
- .add("External storage", external);
return new ReportItem("Storage", R.string.dev_report_storage,
storageInfo);
}
-
private ReportItem getConnectivity() {
MultiReportInfo connectivityInfo = new MultiReportInfo();
@@ -193,7 +212,6 @@ class BriarReportCollector {
Class> clazz = Class.forName(cm.getClass().getName());
Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true);
- //noinspection ConstantConditions
mobileEnabled = (Boolean) method.invoke(cm);
} catch (ClassNotFoundException
| NoSuchMethodException
@@ -201,7 +219,7 @@ class BriarReportCollector {
| InvocationTargetException
| IllegalAccessException e) {
connectivityInfo
- .add("Mobile data reflection exception", e.toString());
+ .add("MobileDataReflectionException", e.toString());
}
// Is mobile data connected ?
boolean mobileConnected = mobile != null && mobile.isConnected();
@@ -213,7 +231,7 @@ class BriarReportCollector {
else mobileStatus += "not enabled, ";
if (mobileConnected) mobileStatus += "connected";
else mobileStatus += "not connected";
- connectivityInfo.add("Mobile data status", mobileStatus);
+ connectivityInfo.add("MobileDataStatus", mobileStatus);
// Is wifi available?
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
@@ -232,13 +250,13 @@ class BriarReportCollector {
else wifiStatus += "not enabled, ";
if (wifiConnected) wifiStatus += "connected";
else wifiStatus += "not connected";
- connectivityInfo.add("Wi-Fi status", wifiStatus);
+ connectivityInfo.add("WiFiStatus", wifiStatus);
// Is wifi direct supported?
String wifiDirectStatus = "Supported";
if (ctx.getSystemService(WIFI_P2P_SERVICE) == null)
- wifiDirectStatus = "Not supported";
- connectivityInfo.add("Wi-Fi Direct", wifiDirectStatus);
+ wifiDirectStatus = "NotSupported";
+ connectivityInfo.add("WiFiDirect", wifiDirectStatus);
if (wm != null) {
WifiInfo wifiInfo = wm.getConnectionInfo();
@@ -252,7 +270,7 @@ class BriarReportCollector {
try {
InetAddress address = InetAddress.getByAddress(ipBytes);
connectivityInfo
- .add("Wi-Fi address", scrubInetAddress(address));
+ .add("Wi-FiAddress", scrubInetAddress(address));
} catch (UnknownHostException ignored) {
// Should only be thrown if address has illegal length
}
@@ -262,7 +280,7 @@ class BriarReportCollector {
// Is Bluetooth available?
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt == null) {
- connectivityInfo.add("Bluetooth status", "Not available");
+ connectivityInfo.add("BluetoothStatus", "Not available");
} else {
// Is Bluetooth enabled?
@SuppressLint("HardwareIds")
@@ -283,7 +301,7 @@ class BriarReportCollector {
else btStatus += "not connectable, ";
if (btDiscoverable) btStatus += "discoverable";
else btStatus += "not discoverable";
- connectivityInfo.add("Bluetooth status", btStatus);
+ connectivityInfo.add("BluetoothStatus", btStatus);
if (SDK_INT >= 21) {
// Is Bluetooth LE scanning and advertising supported?
@@ -295,14 +313,14 @@ class BriarReportCollector {
else btLeStatus = "No scanning, ";
if (btLeAdvertise) btLeStatus += "advertising";
else btLeStatus += "no advertising";
- connectivityInfo.add("Bluetooth LE status", btLeStatus);
+ connectivityInfo.add("BluetoothLeStatus", btLeStatus);
}
Pair p = getBluetoothAddressAndMethod(ctx, bt);
String address = p.getFirst();
String method = p.getSecond();
- connectivityInfo.add("Bluetooth address", scrubMacAddress(address));
- connectivityInfo.add("Bluetooth address method", method);
+ connectivityInfo.add("BluetoothAddress", scrubMacAddress(address));
+ connectivityInfo.add("BluetoothAddressMethod", method);
}
return new ReportItem("Connectivity", R.string.dev_report_connectivity,
connectivityInfo);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashFragment.java
index 00ab9961d..e1d42e118 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashFragment.java
@@ -8,34 +8,34 @@ import android.view.ViewGroup;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.AndroidComponent;
-import org.briarproject.briar.android.BriarApplication;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
-public class CrashFragment extends Fragment {
+public class CrashFragment extends BaseFragment {
+
+ public final static String TAG = CrashFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ }
+
private ReportViewModel viewModel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- FragmentActivity a = requireActivity();
- BriarApplication app =
- (BriarApplication) a.getApplicationContext();
- AndroidComponent androidComponent = app.getApplicationComponent();
- androidComponent.inject(this);
- viewModel = new ViewModelProvider(a, viewModelFactory)
+ viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(ReportViewModel.class);
}
@@ -55,4 +55,9 @@ public class CrashFragment extends Fragment {
return v;
}
+ @Override
+ public String getUniqueTag() {
+ return TAG;
+ }
+
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashReportActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashReportActivity.java
index bd17ea3ab..43c7d40e6 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashReportActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/CrashReportActivity.java
@@ -1,62 +1,60 @@
package org.briarproject.briar.android.reporting;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Process;
import android.widget.Toast;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.AndroidComponent;
-import org.briarproject.briar.android.BriarApplication;
-import org.briarproject.briar.android.Localizer;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.activity.BaseActivity;
+import org.briarproject.briar.android.fragment.BaseFragment;
+import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.logout.HideUiActivity;
import javax.inject.Inject;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
-import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.widget.Toast.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
-import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOTS;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
-public class CrashReportActivity extends AppCompatActivity {
+public class CrashReportActivity extends BaseActivity
+ implements BaseFragmentListener {
- static final String EXTRA_THROWABLE = "throwable";
- static final String EXTRA_APP_START_TIME = "appStartTime";
+ public static final String EXTRA_THROWABLE = "throwable";
+ public static final String EXTRA_APP_START_TIME = "appStartTime";
@Inject
ViewModelProvider.Factory viewModelFactory;
private ReportViewModel viewModel;
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+ }
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
setContentView(R.layout.activity_dev_report);
- AndroidComponent androidComponent =
- ((BriarApplication) getApplication()).getApplicationComponent();
- androidComponent.inject(this);
-
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(ReportViewModel.class);
Intent intent = getIntent();
Throwable t = (Throwable) intent.getSerializableExtra(EXTRA_THROWABLE);
- long appStartTime = intent.getLongExtra(EXTRA_APP_START_TIME, 0);
- viewModel.init(requireNonNull(t), appStartTime);
+ long appStartTime = intent.getLongExtra(EXTRA_APP_START_TIME, -1);
+ viewModel.init(t, appStartTime);
viewModel.getShowReport().observeEvent(this, show -> {
if (show) displayFragment(true);
});
@@ -74,8 +72,8 @@ public class CrashReportActivity extends AppCompatActivity {
}
@Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(Localizer.getInstance().setLocale(base));
+ public void runOnDbThread(Runnable runnable) {
+ throw new AssertionError("deprecated!!!");
}
@Override
@@ -84,7 +82,7 @@ public class CrashReportActivity extends AppCompatActivity {
}
void displayFragment(boolean showReportForm) {
- Fragment f;
+ BaseFragment f;
if (showReportForm) {
f = new ReportFormFragment();
requireNonNull(getSupportActionBar()).show();
@@ -93,7 +91,7 @@ public class CrashReportActivity extends AppCompatActivity {
requireNonNull(getSupportActionBar()).hide();
}
getSupportFragmentManager().beginTransaction()
- .replace(R.id.fragmentContainer, f, f.getTag())
+ .replace(R.id.fragmentContainer, f, f.getUniqueTag())
.commit();
}
@@ -104,6 +102,10 @@ public class CrashReportActivity extends AppCompatActivity {
| FLAG_ACTIVITY_NO_ANIMATION
| FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
+ // crash reports run in their own process that we should kill now
+ // otherwise it keeps running and e.g. doesn't pick up theme changes
+ Process.killProcess(Process.myPid());
+ System.exit(10);
}
finish();
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportData.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportData.java
index 507ca57f1..374e7f486 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportData.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportData.java
@@ -10,11 +10,13 @@ import java.util.Map;
import java.util.TreeMap;
import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.NotThreadSafe;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+@NotThreadSafe
+@NotNullByDefault
class ReportData {
private final ArrayList items = new ArrayList<>();
@@ -28,7 +30,6 @@ class ReportData {
return items;
}
- @NonNull
public JSONObject toJson(boolean includeReport) throws JSONException {
JSONObject json = new JSONObject();
for (ReportItem item : items) {
@@ -48,7 +49,7 @@ class ReportData {
final int nameRes;
final ReportInfo info;
final boolean isOptional;
- volatile boolean isIncluded = true;
+ boolean isIncluded = true;
ReportItem(String name, int nameRes, ReportInfo info) {
this(name, nameRes, info, true);
@@ -91,7 +92,6 @@ class ReportData {
}
}
- @Immutable
@NotNullByDefault
static class MultiReportInfo implements ReportInfo {
private final Map map = new TreeMap<>();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java
index dee217a99..d8daa024c 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportFormFragment.java
@@ -15,14 +15,12 @@ import android.widget.Toast;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.AndroidComponent;
-import org.briarproject.briar.android.BriarApplication;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
@@ -34,7 +32,9 @@ import static java.util.Objects.requireNonNull;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
-public class ReportFormFragment extends Fragment {
+public class ReportFormFragment extends BaseFragment {
+
+ public final static String TAG = ReportFormFragment.class.getName();
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -50,15 +50,16 @@ public class ReportFormFragment extends Fragment {
@Nullable
private MenuItem sendReport;
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ }
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
- FragmentActivity a = requireActivity();
- BriarApplication app = (BriarApplication) a.getApplicationContext();
- AndroidComponent androidComponent = app.getApplicationComponent();
- androidComponent.inject(this);
- viewModel = new ViewModelProvider(a, viewModelFactory)
+ viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(ReportViewModel.class);
}
@@ -131,6 +132,11 @@ public class ReportFormFragment extends Fragment {
return super.onOptionsItemSelected(item);
}
+ @Override
+ public String getUniqueTag() {
+ return TAG;
+ }
+
private void sendReport() {
userCommentView.setEnabled(false);
userEmailView.setEnabled(false);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportViewModel.java
index 719d4ae4e..d0a8015c3 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/ReportViewModel.java
@@ -4,8 +4,7 @@ import android.app.Application;
import android.os.Handler;
import android.os.Looper;
-import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
-import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.plugin.TorConstants;
@@ -13,7 +12,6 @@ import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.reporting.ReportData.MultiReportInfo;
-import org.briarproject.briar.android.util.UserFeedback;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.json.JSONException;
@@ -26,6 +24,7 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
@@ -38,8 +37,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
-@MethodsNotNullByDefault
-@ParametersNotNullByDefault
+@NotNullByDefault
public class ReportViewModel extends AndroidViewModel {
private static final Logger LOG =
@@ -68,11 +66,11 @@ public class ReportViewModel extends AndroidViewModel {
this.pluginManager = pluginManager;
}
- void init(Throwable throwable, long appStartTime) {
- isFeedback = throwable instanceof UserFeedback;
+ void init(@Nullable Throwable t, long appStartTime) {
+ isFeedback = t == null;
if (reportData.getValue() == null) new SingleShotAndroidExecutor(() -> {
- Throwable t = isFeedback ? null : throwable;
- reportData.postValue(collector.collectReportData(t, appStartTime));
+ ReportData data = collector.collectReportData(t, appStartTime);
+ reportData.postValue(data);
}).start();
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
index 1dd20ca53..7412b213f 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
@@ -30,7 +30,6 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.Localizer;
import org.briarproject.briar.android.util.UiUtils;
@@ -93,6 +92,7 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGT
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.SIGN_OUT_URI;
import static org.briarproject.briar.android.util.UiUtils.getCountryDisplayName;
import static org.briarproject.briar.android.util.UiUtils.hasScreenLock;
+import static org.briarproject.briar.android.util.UiUtils.triggerFeedback;
import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_CHANNEL_ID;
@@ -226,9 +226,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
Preference prefFeedback =
requireNonNull(findPreference("pref_key_send_feedback"));
prefFeedback.setOnPreferenceClickListener(preference -> {
- BriarApplication app =
- (BriarApplication) requireContext().getApplicationContext();
- app.triggerFeedback();
+ triggerFeedback(requireContext());
return true;
});
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index d71cdd865..aed5402e2 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -33,6 +33,7 @@ import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
+import org.briarproject.briar.android.reporting.FeedbackActivity;
import org.briarproject.briar.android.view.ArticleMovementMethod;
import org.briarproject.briar.android.widget.LinkDialogFragment;
@@ -49,6 +50,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.text.HtmlCompat;
+import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
@@ -90,6 +92,8 @@ import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.DAYS;
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
+import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME;
+import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_THROWABLE;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -343,6 +347,20 @@ public class UiUtils {
return fm.hasEnrolledFingerprints() && fm.isHardwareDetected();
}
+ public static void triggerFeedback(Context ctx) {
+ startDevReportActivity(ctx, FeedbackActivity.class, null, null);
+ }
+
+ public static void startDevReportActivity(Context ctx,
+ Class extends FragmentActivity> activity, @Nullable Throwable t,
+ @Nullable Long appStartTime) {
+ final Intent dialogIntent = new Intent(ctx, activity);
+ dialogIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+ dialogIntent.putExtra(EXTRA_THROWABLE, t);
+ dialogIntent.putExtra(EXTRA_APP_START_TIME, appStartTime);
+ ctx.startActivity(dialogIntent);
+ }
+
public static boolean enterPressed(int actionId,
@Nullable KeyEvent keyEvent) {
return actionId == IME_NULL &&
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UserFeedback.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UserFeedback.java
deleted file mode 100644
index c02134a75..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UserFeedback.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.briarproject.briar.android.util;
-
-public class UserFeedback extends Exception {
-
-}
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 0d9f7f14e..6798ff921 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -570,6 +570,7 @@
Could not load report data.
Basic information
Device information
+ Stacktrace
Time information
Memory
Storage
@@ -579,7 +580,7 @@
Device Features
Send report
Close
- Trying to send feedback now…
+ Sending feedback…
Feedback sent.
Report saved. It will be sent the next time you log into Briar.
Error: Sending report failed.
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java b/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java
deleted file mode 100644
index e8288eb9e..000000000
--- a/briar-android/src/test/java/org/briarproject/briar/android/TestBriarApplication.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.briarproject.briar.android;
-
-import android.app.Application;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-import com.vanniktech.emoji.EmojiManager;
-import com.vanniktech.emoji.google.GoogleEmojiProvider;
-
-import org.briarproject.bramble.BrambleAndroidEagerSingletons;
-import org.briarproject.bramble.BrambleAppComponent;
-import org.briarproject.bramble.BrambleCoreEagerSingletons;
-import org.briarproject.briar.BriarCoreEagerSingletons;
-
-import java.util.Collection;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-
-import static java.util.Collections.emptyList;
-
-/**
- * This class only exists to avoid static initialisation of ACRA
- */
-public class TestBriarApplication extends Application
- implements BriarApplication {
-
- private static final Logger LOG =
- Logger.getLogger(TestBriarApplication.class.getName());
-
- private AndroidComponent applicationComponent;
- private volatile SharedPreferences prefs;
-
- @Override
- public void onCreate() {
- super.onCreate();
- LOG.info("Created");
-
- prefs = PreferenceManager.getDefaultSharedPreferences(this);
- Localizer.initialize(prefs);
- applicationComponent = DaggerAndroidComponent.builder()
- .appModule(new AppModule(this))
- .build();
-
- // We need to load the eager singletons directly after making the
- // dependency graphs
- BrambleCoreEagerSingletons.Helper
- .injectEagerSingletons(applicationComponent);
- BrambleAndroidEagerSingletons.Helper
- .injectEagerSingletons(applicationComponent);
- BriarCoreEagerSingletons.Helper
- .injectEagerSingletons(applicationComponent);
- AndroidEagerSingletons.Helper
- .injectEagerSingletons(applicationComponent);
- EmojiManager.install(new GoogleEmojiProvider());
- }
-
- @Override
- public BrambleAppComponent getBrambleAppComponent() {
- return applicationComponent;
- }
-
- @Override
- public Collection getRecentLogRecords() {
- return emptyList();
- }
-
- @Override
- public AndroidComponent getApplicationComponent() {
- return applicationComponent;
- }
-
- @Override
- public SharedPreferences getDefaultSharedPreferences() {
- return prefs;
- }
-
- @Override
- public void triggerFeedback() {
- }
-
- @Override
- public boolean isRunningInBackground() {
- return false;
- }
-}
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
index 9edfd6f3d..59cb210ce 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
@@ -3,7 +3,6 @@ package org.briarproject.briar.android.account;
import android.view.View;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.TestBriarApplication;
import org.briarproject.briar.android.login.StrengthMeter;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -42,7 +41,7 @@ import static org.briarproject.briar.android.login.StrengthMeter.YELLOW;
import static org.hamcrest.Matchers.not;
@RunWith(AndroidJUnit4.class)
-@Config(sdk = 21, application = TestBriarApplication.class)
+@Config(sdk = 21)
public class SetupActivityTest {
@Rule
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
index 7b542fc9e..5a8892f9b 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/forum/ForumActivityTest.java
@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.sync.MessageId;
-import org.briarproject.briar.android.TestBriarApplication;
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
import org.briarproject.briar.android.threaded.ThreadItemAdapter;
import org.briarproject.briar.android.threaded.ThreadItemList;
@@ -36,7 +35,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@RunWith(RobolectricTestRunner.class)
-@Config(sdk = 21, application = TestBriarApplication.class)
+@Config(sdk = 21)
public class ForumActivityTest {
private final static MessageId[] MESSAGE_IDS = new MessageId[6];
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordActivityTest.java
index 444fe0a3d..aec8a4558 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordActivityTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordActivityTest.java
@@ -7,7 +7,6 @@ import com.google.android.material.textfield.TextInputLayout;
import org.briarproject.bramble.api.crypto.DecryptionResult;
import org.briarproject.briar.R;
-import org.briarproject.briar.android.TestBriarApplication;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.junit.Assert;
import org.junit.Before;
@@ -36,7 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
-@Config(sdk = 21, application = TestBriarApplication.class)
+@Config(sdk = 21)
public class ChangePasswordActivityTest {
private ChangePasswordActivity changePasswordActivity;