Address review feedback for ACRA replacement

This commit is contained in:
Torsten Grote
2020-12-11 10:38:15 -03:00
parent f9a8fcb207
commit bed3abfd40
22 changed files with 173 additions and 256 deletions

View File

@@ -79,11 +79,8 @@
android:windowSoftInputMode="adjustResize|stateHidden" /> android:windowSoftInputMode="adjustResize|stateHidden" />
<activity <activity
android:name="org.briarproject.briar.android.reporting.FeedbackActivity" android:name="org.briarproject.briar.android.reporting.FeedbackActivity"
android:excludeFromRecents="true"
android:exported="false" android:exported="false"
android:finishOnTaskLaunch="true"
android:label="@string/feedback_title" android:label="@string/feedback_title"
android:launchMode="singleInstance"
android:theme="@style/BriarTheme.NoActionBar" android:theme="@style/BriarTheme.NoActionBar"
android:windowSoftInputMode="adjustResize|stateHidden" /> android:windowSoftInputMode="adjustResize|stateHidden" />

View File

@@ -33,9 +33,6 @@ import org.briarproject.briar.BriarCoreModule;
import org.briarproject.briar.android.attachment.AttachmentModule; import org.briarproject.briar.android.attachment.AttachmentModule;
import org.briarproject.briar.android.conversation.glide.BriarModelLoader; import org.briarproject.briar.android.conversation.glide.BriarModelLoader;
import org.briarproject.briar.android.login.SignInReminderReceiver; 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.android.view.EmojiTextInputView;
import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog; import org.briarproject.briar.api.android.DozeWatchdog;
@@ -175,10 +172,6 @@ public interface AndroidComponent
void inject(BriarService briarService); void inject(BriarService briarService);
void inject(CrashReportActivity crashReportActivity);
void inject(ReportFormFragment reportFormFragment);
void inject(CrashFragment crashFragment);
void inject(NotificationCleanupService notificationCleanupService); void inject(NotificationCleanupService notificationCleanupService);
void inject(EmojiTextInputView textInputView); void inject(EmojiTextInputView textInputView);

View File

@@ -23,7 +23,5 @@ public interface BriarApplication extends BrambleApplication {
SharedPreferences getDefaultSharedPreferences(); SharedPreferences getDefaultSharedPreferences();
void triggerFeedback();
boolean isRunningInBackground(); boolean isRunningInBackground();
} }

View File

@@ -151,11 +151,6 @@ public class BriarApplicationImpl extends Application
return prefs; return prefs;
} }
@Override
public void triggerFeedback() {
exceptionHandler.feedback();
}
@Override @Override
public boolean isRunningInBackground() { public boolean isRunningInBackground() {
RunningAppProcessInfo info = new RunningAppProcessInfo(); RunningAppProcessInfo info = new RunningAppProcessInfo();

View File

@@ -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.GroupRevealModule;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity; import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment; 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.SettingsActivity;
import org.briarproject.briar.android.settings.SettingsFragment; import org.briarproject.briar.android.settings.SettingsFragment;
import org.briarproject.briar.android.sharing.BlogInvitationActivity; import org.briarproject.briar.android.sharing.BlogInvitationActivity;
@@ -184,6 +187,8 @@ public interface ActivityComponent {
void inject(PendingContactListActivity activity); void inject(PendingContactListActivity activity);
void inject(CrashReportActivity crashReportActivity);
// Fragments // Fragments
void inject(AuthorNameFragment fragment); void inject(AuthorNameFragment fragment);
@@ -234,4 +239,8 @@ public interface ActivityComponent {
void inject(ImageFragment imageFragment); void inject(ImageFragment imageFragment);
void inject(ReportFormFragment reportFormFragment);
void inject(CrashFragment crashFragment);
} }

View File

@@ -18,7 +18,6 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.forum.ForumModule; import org.briarproject.briar.android.forum.ForumModule;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment; 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.util.UiUtils;
import org.briarproject.briar.android.widget.TapSafeFrameLayout; import org.briarproject.briar.android.widget.TapSafeFrameLayout;
import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener; 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}. * Warning: Some activities don't extend {@link BaseActivity}.
* E.g. {@link CrashReportActivity}
*/ */
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -123,6 +121,7 @@ public abstract class BaseActivity extends AppCompatActivity
return new ActivityModule(this); return new ActivityModule(this);
} }
// TODO use a test module where this is used in tests
protected ForumModule getForumModule() { protected ForumModule getForumModule() {
return new ForumModule(); return new ForumModule();
} }

View File

@@ -10,13 +10,10 @@ import android.widget.TextView;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.util.UiUtils;
import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
@@ -41,9 +38,6 @@ public class ContactExchangeErrorFragment extends BaseFragment {
return f; return f;
} }
@Inject
AndroidExecutor androidExecutor;
@Override @Override
public String getUniqueTag() { public String getUniqueTag() {
return TAG; return TAG;
@@ -88,10 +82,8 @@ public class ContactExchangeErrorFragment extends BaseFragment {
} }
private void triggerFeedback() { private void triggerFeedback() {
BriarApplication app = UiUtils.triggerFeedback(requireContext());
(BriarApplication) requireContext().getApplicationContext();
finish(); finish();
app.triggerFeedback();
} }
} }

View File

@@ -1,19 +1,13 @@
package org.briarproject.briar.android.reporting; package org.briarproject.briar.android.reporting;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.Process; import android.os.Process;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.util.UserFeedback;
import java.lang.Thread.UncaughtExceptionHandler; import java.lang.Thread.UncaughtExceptionHandler;
import androidx.fragment.app.FragmentActivity; import static org.briarproject.briar.android.util.UiUtils.startDevReportActivity;
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;
@NotNullByDefault @NotNullByDefault
public class BriarExceptionHandler implements UncaughtExceptionHandler { public class BriarExceptionHandler implements UncaughtExceptionHandler {
@@ -29,22 +23,9 @@ public class BriarExceptionHandler implements UncaughtExceptionHandler {
@Override @Override
public void uncaughtException(Thread t, Throwable e) { public void uncaughtException(Thread t, Throwable e) {
// activity runs in its own process, so we can kill the old one // 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()); Process.killProcess(Process.myPid());
System.exit(10); 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);
}
} }

View File

@@ -21,12 +21,14 @@ import android.os.Build;
import android.os.Environment; import android.os.Environment;
import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.BuildConfig; import org.briarproject.briar.BuildConfig;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.logging.BriefLogFormatter; import org.briarproject.briar.android.logging.BriefLogFormatter;
import org.briarproject.briar.android.reporting.ReportData.MultiReportInfo; import org.briarproject.briar.android.reporting.ReportData.MultiReportInfo;
import org.briarproject.briar.android.reporting.ReportData.ReportItem; import org.briarproject.briar.android.reporting.ReportData.ReportItem;
import org.briarproject.briar.android.reporting.ReportData.SingleReportInfo;
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -40,6 +42,8 @@ import java.util.Date;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
import javax.annotation.concurrent.Immutable;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE; 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.PrivacyUtils.scrubMacAddress;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@Immutable
@NotNullByDefault
class BriarReportCollector { class BriarReportCollector {
private final Context ctx; private final Context ctx;
@@ -66,9 +72,11 @@ class BriarReportCollector {
public ReportData collectReportData(@Nullable Throwable t, public ReportData collectReportData(@Nullable Throwable t,
long appStartTime) { long appStartTime) {
return new ReportData() ReportData reportData = new ReportData()
.add(getBasicInfo(t)) .add(getBasicInfo(t))
.add(getDeviceInfo()) .add(getDeviceInfo());
if (t != null) reportData.add(getStacktrace(t));
return reportData
.add(getTimeInfo(appStartTime)) .add(getTimeInfo(appStartTime))
.add(getMemory()) .add(getMemory())
.add(getStorage()) .add(getStorage())
@@ -91,27 +99,18 @@ class BriarReportCollector {
versionCode = "?"; versionCode = "?";
} }
MultiReportInfo basicInfo = new MultiReportInfo() MultiReportInfo basicInfo = new MultiReportInfo()
.add("Package name", packageName) .add("PackageName", packageName)
.add("Version name", versionName) .add("VersionName", versionName)
.add("Version code", versionCode); .add("VersionCode", versionCode)
// print stacktrace of Throwable if this is not feedback .add("isCrashReport", String.valueOf(t != null));
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());
}
return new ReportItem("BasicInfo", R.string.dev_report_basic_info, return new ReportItem("BasicInfo", R.string.dev_report_basic_info,
basicInfo, false); basicInfo, false);
} }
private ReportItem getDeviceInfo() { private ReportItem getDeviceInfo() {
MultiReportInfo deviceInfo = new MultiReportInfo() MultiReportInfo deviceInfo = new MultiReportInfo()
.add("Android version", Build.VERSION.RELEASE) .add("AndroidVersion", Build.VERSION.RELEASE)
.add("Android SDK API", String.valueOf(SDK_INT)) .add("AndroidApi", String.valueOf(SDK_INT))
.add("Product", Build.PRODUCT) .add("Product", Build.PRODUCT)
.add("Model", Build.MODEL) .add("Model", Build.MODEL)
.add("Brand", Build.BRAND); .add("Brand", Build.BRAND);
@@ -119,10 +118,24 @@ class BriarReportCollector {
deviceInfo); 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) { private ReportItem getTimeInfo(long startTime) {
MultiReportInfo timeInfo = new MultiReportInfo() MultiReportInfo timeInfo = new MultiReportInfo()
.add("App start time", formatTime(startTime)) .add("ReportTime", formatTime(System.currentTimeMillis()));
.add("Crash time", formatTime(System.currentTimeMillis())); if (startTime > -1) {
timeInfo.add("AppStartTime", formatTime(startTime));
}
return new ReportItem("DeviceInfo", R.string.dev_report_time_info, return new ReportItem("DeviceInfo", R.string.dev_report_time_info,
timeInfo); timeInfo);
} }
@@ -132,53 +145,59 @@ class BriarReportCollector {
} }
private ReportItem getMemory() { private ReportItem getMemory() {
MultiReportInfo memInfo = new MultiReportInfo();
// System memory // System memory
ActivityManager am = getSystemService(ctx, ActivityManager.class); ActivityManager am = getSystemService(ctx, ActivityManager.class);
ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo(); ActivityManager.MemoryInfo mem = new ActivityManager.MemoryInfo();
requireNonNull(am).getMemoryInfo(mem); requireNonNull(am).getMemoryInfo(mem);
String systemMemory; String systemTotal = (mem.totalMem / 1024 / 1024) + " MiB";
systemMemory = (mem.totalMem / 1024 / 1024) + " MiB total, " String systemFree = (mem.availMem / 1024 / 1024) + " MiB";
+ (mem.availMem / 1024 / 1204) + " MiB free, " String systemThreshold = (mem.threshold / 1024 / 1024) + " MiB";
+ (mem.threshold / 1024 / 1024) + " MiB threshold"; memInfo.add("SystemMemoryTotal", systemTotal);
memInfo.add("SystemMemoryFree", systemFree);
memInfo.add("SystemMemoryThreshold", systemThreshold);
// Virtual machine memory // Virtual machine memory
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
long heap = runtime.totalMemory(); long heap = runtime.totalMemory();
long heapFree = runtime.freeMemory(); long heapFree = runtime.freeMemory();
long heapMax = runtime.maxMemory(); long heapMax = runtime.maxMemory();
String vmMemory = (heap / 1024 / 1024) + " MiB allocated, " String vmMemoryAllocated = (heap / 1024 / 1024) + " MiB";
+ (heapFree / 1024 / 1024) + " MiB free, " String vmMemoryFree = (heapFree / 1024 / 1024) + " MiB";
+ (heapMax / 1024 / 1024) + " MiB maximum"; 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); return new ReportItem("Memory", R.string.dev_report_memory, memInfo);
} }
private ReportItem getStorage() { private ReportItem getStorage() {
MultiReportInfo storageInfo = new MultiReportInfo();
// Internal storage // Internal storage
File root = Environment.getRootDirectory(); File root = Environment.getRootDirectory();
long rootTotal = root.getTotalSpace(); long rootTotal = root.getTotalSpace();
long rootFree = root.getFreeSpace(); long rootFree = root.getFreeSpace();
String internal = (rootTotal / 1024 / 1024) + " MiB total, " storageInfo.add("InternalStorageTotal",
+ (rootFree / 1024 / 1024) + " MiB free"; (rootTotal / 1024 / 1024) + " MiB");
storageInfo.add("InternalStorageFree",
(rootFree / 1024 / 1024) + " MiB");
// External storage (SD card) // External storage (SD card)
File sd = Environment.getExternalStorageDirectory(); File sd = Environment.getExternalStorageDirectory();
long sdTotal = sd.getTotalSpace(); long sdTotal = sd.getTotalSpace();
long sdFree = sd.getFreeSpace(); long sdFree = sd.getFreeSpace();
String external = (sdTotal / 1024 / 1024) + " MiB total, " storageInfo.add("ExternalStorageTotal",
+ (sdFree / 1024 / 1024) + " MiB free"; (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, return new ReportItem("Storage", R.string.dev_report_storage,
storageInfo); storageInfo);
} }
private ReportItem getConnectivity() { private ReportItem getConnectivity() {
MultiReportInfo connectivityInfo = new MultiReportInfo(); MultiReportInfo connectivityInfo = new MultiReportInfo();
@@ -193,7 +212,6 @@ class BriarReportCollector {
Class<?> clazz = Class.forName(cm.getClass().getName()); Class<?> clazz = Class.forName(cm.getClass().getName());
Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); method.setAccessible(true);
//noinspection ConstantConditions
mobileEnabled = (Boolean) method.invoke(cm); mobileEnabled = (Boolean) method.invoke(cm);
} catch (ClassNotFoundException } catch (ClassNotFoundException
| NoSuchMethodException | NoSuchMethodException
@@ -201,7 +219,7 @@ class BriarReportCollector {
| InvocationTargetException | InvocationTargetException
| IllegalAccessException e) { | IllegalAccessException e) {
connectivityInfo connectivityInfo
.add("Mobile data reflection exception", e.toString()); .add("MobileDataReflectionException", e.toString());
} }
// Is mobile data connected ? // Is mobile data connected ?
boolean mobileConnected = mobile != null && mobile.isConnected(); boolean mobileConnected = mobile != null && mobile.isConnected();
@@ -213,7 +231,7 @@ class BriarReportCollector {
else mobileStatus += "not enabled, "; else mobileStatus += "not enabled, ";
if (mobileConnected) mobileStatus += "connected"; if (mobileConnected) mobileStatus += "connected";
else mobileStatus += "not connected"; else mobileStatus += "not connected";
connectivityInfo.add("Mobile data status", mobileStatus); connectivityInfo.add("MobileDataStatus", mobileStatus);
// Is wifi available? // Is wifi available?
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
@@ -232,13 +250,13 @@ class BriarReportCollector {
else wifiStatus += "not enabled, "; else wifiStatus += "not enabled, ";
if (wifiConnected) wifiStatus += "connected"; if (wifiConnected) wifiStatus += "connected";
else wifiStatus += "not connected"; else wifiStatus += "not connected";
connectivityInfo.add("Wi-Fi status", wifiStatus); connectivityInfo.add("WiFiStatus", wifiStatus);
// Is wifi direct supported? // Is wifi direct supported?
String wifiDirectStatus = "Supported"; String wifiDirectStatus = "Supported";
if (ctx.getSystemService(WIFI_P2P_SERVICE) == null) if (ctx.getSystemService(WIFI_P2P_SERVICE) == null)
wifiDirectStatus = "Not supported"; wifiDirectStatus = "NotSupported";
connectivityInfo.add("Wi-Fi Direct", wifiDirectStatus); connectivityInfo.add("WiFiDirect", wifiDirectStatus);
if (wm != null) { if (wm != null) {
WifiInfo wifiInfo = wm.getConnectionInfo(); WifiInfo wifiInfo = wm.getConnectionInfo();
@@ -252,7 +270,7 @@ class BriarReportCollector {
try { try {
InetAddress address = InetAddress.getByAddress(ipBytes); InetAddress address = InetAddress.getByAddress(ipBytes);
connectivityInfo connectivityInfo
.add("Wi-Fi address", scrubInetAddress(address)); .add("Wi-FiAddress", scrubInetAddress(address));
} catch (UnknownHostException ignored) { } catch (UnknownHostException ignored) {
// Should only be thrown if address has illegal length // Should only be thrown if address has illegal length
} }
@@ -262,7 +280,7 @@ class BriarReportCollector {
// Is Bluetooth available? // Is Bluetooth available?
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt == null) { if (bt == null) {
connectivityInfo.add("Bluetooth status", "Not available"); connectivityInfo.add("BluetoothStatus", "Not available");
} else { } else {
// Is Bluetooth enabled? // Is Bluetooth enabled?
@SuppressLint("HardwareIds") @SuppressLint("HardwareIds")
@@ -283,7 +301,7 @@ class BriarReportCollector {
else btStatus += "not connectable, "; else btStatus += "not connectable, ";
if (btDiscoverable) btStatus += "discoverable"; if (btDiscoverable) btStatus += "discoverable";
else btStatus += "not discoverable"; else btStatus += "not discoverable";
connectivityInfo.add("Bluetooth status", btStatus); connectivityInfo.add("BluetoothStatus", btStatus);
if (SDK_INT >= 21) { if (SDK_INT >= 21) {
// Is Bluetooth LE scanning and advertising supported? // Is Bluetooth LE scanning and advertising supported?
@@ -295,14 +313,14 @@ class BriarReportCollector {
else btLeStatus = "No scanning, "; else btLeStatus = "No scanning, ";
if (btLeAdvertise) btLeStatus += "advertising"; if (btLeAdvertise) btLeStatus += "advertising";
else btLeStatus += "no advertising"; else btLeStatus += "no advertising";
connectivityInfo.add("Bluetooth LE status", btLeStatus); connectivityInfo.add("BluetoothLeStatus", btLeStatus);
} }
Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt); Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt);
String address = p.getFirst(); String address = p.getFirst();
String method = p.getSecond(); String method = p.getSecond();
connectivityInfo.add("Bluetooth address", scrubMacAddress(address)); connectivityInfo.add("BluetoothAddress", scrubMacAddress(address));
connectivityInfo.add("Bluetooth address method", method); connectivityInfo.add("BluetoothAddressMethod", method);
} }
return new ReportItem("Connectivity", R.string.dev_report_connectivity, return new ReportItem("Connectivity", R.string.dev_report_connectivity,
connectivityInfo); connectivityInfo);

View File

@@ -8,34 +8,34 @@ import android.view.ViewGroup;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.AndroidComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class CrashFragment extends Fragment { public class CrashFragment extends BaseFragment {
public final static String TAG = CrashFragment.class.getName();
@Inject @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
private ReportViewModel viewModel; private ReportViewModel viewModel;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
FragmentActivity a = requireActivity(); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
BriarApplication app =
(BriarApplication) a.getApplicationContext();
AndroidComponent androidComponent = app.getApplicationComponent();
androidComponent.inject(this);
viewModel = new ViewModelProvider(a, viewModelFactory)
.get(ReportViewModel.class); .get(ReportViewModel.class);
} }
@@ -55,4 +55,9 @@ public class CrashFragment extends Fragment {
return v; return v;
} }
@Override
public String getUniqueTag() {
return TAG;
}
} }

View File

@@ -1,62 +1,60 @@
package org.briarproject.briar.android.reporting; package org.briarproject.briar.android.reporting;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process;
import android.widget.Toast; import android.widget.Toast;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.AndroidComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.logout.HideUiActivity; import org.briarproject.briar.android.logout.HideUiActivity;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; 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_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; 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 android.widget.Toast.LENGTH_LONG;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOTS;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class CrashReportActivity extends AppCompatActivity { public class CrashReportActivity extends BaseActivity
implements BaseFragmentListener {
static final String EXTRA_THROWABLE = "throwable"; public static final String EXTRA_THROWABLE = "throwable";
static final String EXTRA_APP_START_TIME = "appStartTime"; public static final String EXTRA_APP_START_TIME = "appStartTime";
@Inject @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
private ReportViewModel viewModel; private ReportViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
setContentView(R.layout.activity_dev_report); setContentView(R.layout.activity_dev_report);
AndroidComponent androidComponent =
((BriarApplication) getApplication()).getApplicationComponent();
androidComponent.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory) viewModel = new ViewModelProvider(this, viewModelFactory)
.get(ReportViewModel.class); .get(ReportViewModel.class);
Intent intent = getIntent(); Intent intent = getIntent();
Throwable t = (Throwable) intent.getSerializableExtra(EXTRA_THROWABLE); Throwable t = (Throwable) intent.getSerializableExtra(EXTRA_THROWABLE);
long appStartTime = intent.getLongExtra(EXTRA_APP_START_TIME, 0); long appStartTime = intent.getLongExtra(EXTRA_APP_START_TIME, -1);
viewModel.init(requireNonNull(t), appStartTime); viewModel.init(t, appStartTime);
viewModel.getShowReport().observeEvent(this, show -> { viewModel.getShowReport().observeEvent(this, show -> {
if (show) displayFragment(true); if (show) displayFragment(true);
}); });
@@ -74,8 +72,8 @@ public class CrashReportActivity extends AppCompatActivity {
} }
@Override @Override
protected void attachBaseContext(Context base) { public void runOnDbThread(Runnable runnable) {
super.attachBaseContext(Localizer.getInstance().setLocale(base)); throw new AssertionError("deprecated!!!");
} }
@Override @Override
@@ -84,7 +82,7 @@ public class CrashReportActivity extends AppCompatActivity {
} }
void displayFragment(boolean showReportForm) { void displayFragment(boolean showReportForm) {
Fragment f; BaseFragment f;
if (showReportForm) { if (showReportForm) {
f = new ReportFormFragment(); f = new ReportFormFragment();
requireNonNull(getSupportActionBar()).show(); requireNonNull(getSupportActionBar()).show();
@@ -93,7 +91,7 @@ public class CrashReportActivity extends AppCompatActivity {
requireNonNull(getSupportActionBar()).hide(); requireNonNull(getSupportActionBar()).hide();
} }
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, f, f.getTag()) .replace(R.id.fragmentContainer, f, f.getUniqueTag())
.commit(); .commit();
} }
@@ -104,6 +102,10 @@ public class CrashReportActivity extends AppCompatActivity {
| FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_NO_ANIMATION
| FLAG_ACTIVITY_CLEAR_TASK); | FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i); 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(); finish();
} }

View File

@@ -10,11 +10,13 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
@NotThreadSafe
@NotNullByDefault
class ReportData { class ReportData {
private final ArrayList<ReportItem> items = new ArrayList<>(); private final ArrayList<ReportItem> items = new ArrayList<>();
@@ -28,7 +30,6 @@ class ReportData {
return items; return items;
} }
@NonNull
public JSONObject toJson(boolean includeReport) throws JSONException { public JSONObject toJson(boolean includeReport) throws JSONException {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
for (ReportItem item : items) { for (ReportItem item : items) {
@@ -48,7 +49,7 @@ class ReportData {
final int nameRes; final int nameRes;
final ReportInfo info; final ReportInfo info;
final boolean isOptional; final boolean isOptional;
volatile boolean isIncluded = true; boolean isIncluded = true;
ReportItem(String name, int nameRes, ReportInfo info) { ReportItem(String name, int nameRes, ReportInfo info) {
this(name, nameRes, info, true); this(name, nameRes, info, true);
@@ -91,7 +92,6 @@ class ReportData {
} }
} }
@Immutable
@NotNullByDefault @NotNullByDefault
static class MultiReportInfo implements ReportInfo { static class MultiReportInfo implements ReportInfo {
private final Map<String, String> map = new TreeMap<>(); private final Map<String, String> map = new TreeMap<>();

View File

@@ -15,14 +15,12 @@ import android.widget.Toast;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.AndroidComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.BriarApplication; import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -34,7 +32,9 @@ import static java.util.Objects.requireNonNull;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class ReportFormFragment extends Fragment { public class ReportFormFragment extends BaseFragment {
public final static String TAG = ReportFormFragment.class.getName();
@Inject @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
@@ -50,15 +50,16 @@ public class ReportFormFragment extends Fragment {
@Nullable @Nullable
private MenuItem sendReport; private MenuItem sendReport;
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
FragmentActivity a = requireActivity(); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
BriarApplication app = (BriarApplication) a.getApplicationContext();
AndroidComponent androidComponent = app.getApplicationComponent();
androidComponent.inject(this);
viewModel = new ViewModelProvider(a, viewModelFactory)
.get(ReportViewModel.class); .get(ReportViewModel.class);
} }
@@ -131,6 +132,11 @@ public class ReportFormFragment extends Fragment {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override
public String getUniqueTag() {
return TAG;
}
private void sendReport() { private void sendReport() {
userCommentView.setEnabled(false); userCommentView.setEnabled(false);
userEmailView.setEnabled(false); userEmailView.setEnabled(false);

View File

@@ -4,8 +4,7 @@ import android.app.Application;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.plugin.TorConstants; 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.bramble.util.AndroidUtils;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.reporting.ReportData.MultiReportInfo; 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.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.json.JSONException; import org.json.JSONException;
@@ -26,6 +24,7 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData; 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.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@MethodsNotNullByDefault @NotNullByDefault
@ParametersNotNullByDefault
public class ReportViewModel extends AndroidViewModel { public class ReportViewModel extends AndroidViewModel {
private static final Logger LOG = private static final Logger LOG =
@@ -68,11 +66,11 @@ public class ReportViewModel extends AndroidViewModel {
this.pluginManager = pluginManager; this.pluginManager = pluginManager;
} }
void init(Throwable throwable, long appStartTime) { void init(@Nullable Throwable t, long appStartTime) {
isFeedback = throwable instanceof UserFeedback; isFeedback = t == null;
if (reportData.getValue() == null) new SingleShotAndroidExecutor(() -> { if (reportData.getValue() == null) new SingleShotAndroidExecutor(() -> {
Throwable t = isFeedback ? null : throwable; ReportData data = collector.collectReportData(t, appStartTime);
reportData.postValue(collector.collectReportData(t, appStartTime)); reportData.postValue(data);
}).start(); }).start();
} }

View File

@@ -30,7 +30,6 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.Localizer;
import org.briarproject.briar.android.util.UiUtils; 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.navdrawer.NavDrawerActivity.SIGN_OUT_URI;
import static org.briarproject.briar.android.util.UiUtils.getCountryDisplayName; 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.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.BLOG_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_CHANNEL_ID; import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_CHANNEL_ID; import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_CHANNEL_ID;
@@ -226,9 +226,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
Preference prefFeedback = Preference prefFeedback =
requireNonNull(findPreference("pref_key_send_feedback")); requireNonNull(findPreference("pref_key_send_feedback"));
prefFeedback.setOnPreferenceClickListener(preference -> { prefFeedback.setOnPreferenceClickListener(preference -> {
BriarApplication app = triggerFeedback(requireContext());
(BriarApplication) requireContext().getApplicationContext();
app.triggerFeedback();
return true; return true;
}); });

View File

@@ -33,6 +33,7 @@ import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.reporting.FeedbackActivity;
import org.briarproject.briar.android.view.ArticleMovementMethod; import org.briarproject.briar.android.view.ArticleMovementMethod;
import org.briarproject.briar.android.widget.LinkDialogFragment; import org.briarproject.briar.android.widget.LinkDialogFragment;
@@ -49,6 +50,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat; import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.text.HtmlCompat; import androidx.core.text.HtmlCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
@@ -90,6 +92,8 @@ import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.DAYS;
import static org.briarproject.briar.BuildConfig.APPLICATION_ID; import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE; 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 @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -343,6 +347,20 @@ public class UiUtils {
return fm.hasEnrolledFingerprints() && fm.isHardwareDetected(); 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, public static boolean enterPressed(int actionId,
@Nullable KeyEvent keyEvent) { @Nullable KeyEvent keyEvent) {
return actionId == IME_NULL && return actionId == IME_NULL &&

View File

@@ -1,5 +0,0 @@
package org.briarproject.briar.android.util;
public class UserFeedback extends Exception {
}

View File

@@ -570,6 +570,7 @@
<string name="could_not_load_report_data">Could not load report data.</string> <string name="could_not_load_report_data">Could not load report data.</string>
<string name="dev_report_basic_info">Basic information</string> <string name="dev_report_basic_info">Basic information</string>
<string name="dev_report_device_info">Device information</string> <string name="dev_report_device_info">Device information</string>
<string name="dev_report_stacktrace">Stacktrace</string>
<string name="dev_report_time_info">Time information</string> <string name="dev_report_time_info">Time information</string>
<string name="dev_report_memory">Memory</string> <string name="dev_report_memory">Memory</string>
<string name="dev_report_storage">Storage</string> <string name="dev_report_storage">Storage</string>
@@ -579,7 +580,7 @@
<string name="dev_report_device_features">Device Features</string> <string name="dev_report_device_features">Device Features</string>
<string name="send_report">Send report</string> <string name="send_report">Send report</string>
<string name="close">Close</string> <string name="close">Close</string>
<string name="dev_report_sending">Trying to send feedback now</string> <string name="dev_report_sending">Sending feedback…</string>
<string name="dev_report_sent">Feedback sent.</string> <string name="dev_report_sent">Feedback sent.</string>
<string name="dev_report_saved">Report saved. It will be sent the next time you log into Briar.</string> <string name="dev_report_saved">Report saved. It will be sent the next time you log into Briar.</string>
<string name="dev_report_error">Error: Sending report failed.</string> <string name="dev_report_error">Error: Sending report failed.</string>

View File

@@ -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<LogRecord> 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;
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.briar.android.account;
import android.view.View; import android.view.View;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.TestBriarApplication;
import org.briarproject.briar.android.login.StrengthMeter; import org.briarproject.briar.android.login.StrengthMeter;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
@@ -42,7 +41,7 @@ import static org.briarproject.briar.android.login.StrengthMeter.YELLOW;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@Config(sdk = 21, application = TestBriarApplication.class) @Config(sdk = 21)
public class SetupActivityTest { public class SetupActivityTest {
@Rule @Rule

View File

@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorInfo; import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.sync.MessageId; 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.controller.handler.UiResultExceptionHandler;
import org.briarproject.briar.android.threaded.ThreadItemAdapter; import org.briarproject.briar.android.threaded.ThreadItemAdapter;
import org.briarproject.briar.android.threaded.ThreadItemList; import org.briarproject.briar.android.threaded.ThreadItemList;
@@ -36,7 +35,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 21, application = TestBriarApplication.class) @Config(sdk = 21)
public class ForumActivityTest { public class ForumActivityTest {
private final static MessageId[] MESSAGE_IDS = new MessageId[6]; private final static MessageId[] MESSAGE_IDS = new MessageId[6];

View File

@@ -7,7 +7,6 @@ import com.google.android.material.textfield.TextInputLayout;
import org.briarproject.bramble.api.crypto.DecryptionResult; import org.briarproject.bramble.api.crypto.DecryptionResult;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.TestBriarApplication;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@@ -36,7 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(sdk = 21, application = TestBriarApplication.class) @Config(sdk = 21)
public class ChangePasswordActivityTest { public class ChangePasswordActivityTest {
private ChangePasswordActivity changePasswordActivity; private ChangePasswordActivity changePasswordActivity;