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" />
<activity
android:name="org.briarproject.briar.android.reporting.FeedbackActivity"
android:excludeFromRecents="true"
android:exported="false"
android:finishOnTaskLaunch="true"
android:label="@string/feedback_title"
android:launchMode="singleInstance"
android:theme="@style/BriarTheme.NoActionBar"
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.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);

View File

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

View File

@@ -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();

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.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);
}

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.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();
}

View File

@@ -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();
}
}

View File

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

View File

@@ -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<String, String> 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);

View File

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

View File

@@ -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();
}

View File

@@ -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<ReportItem> 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<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.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);

View File

@@ -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();
}

View File

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

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.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 &&

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="dev_report_basic_info">Basic 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_memory">Memory</string>
<string name="dev_report_storage">Storage</string>
@@ -579,7 +580,7 @@
<string name="dev_report_device_features">Device Features</string>
<string name="send_report">Send report</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_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>

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 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

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.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];

View File

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