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 232ff7474..9f8e4ba29 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 @@ -36,7 +36,7 @@ import org.briarproject.briar.android.attachment.AttachmentModule; import org.briarproject.briar.android.attachment.media.MediaModule; import org.briarproject.briar.android.conversation.glide.BriarModelLoader; import org.briarproject.briar.android.hotspot.AbstractTabsFragment; -import org.briarproject.briar.android.hotspot.HotspotHelpFragment; +import org.briarproject.briar.android.hotspot.FallbackFragment; import org.briarproject.briar.android.hotspot.HotspotIntroFragment; import org.briarproject.briar.android.hotspot.ManualHotspotFragment; import org.briarproject.briar.android.hotspot.QrHotspotFragment; @@ -224,5 +224,5 @@ public interface AndroidComponent void inject(ManualHotspotFragment manualHotspotFragment); - void inject(HotspotHelpFragment hotspotHelpFragment); + void inject(FallbackFragment fallbackFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java index 201e313ec..c6e1d85f8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ErrorFragment.java @@ -40,8 +40,7 @@ public class ErrorFragment extends BaseFragment { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Bundle args = getArguments(); - if (args == null) throw new AssertionError(); + Bundle args = requireArguments(); errorMessage = args.getString(ERROR_MSG); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java new file mode 100644 index 000000000..7b8d3702d --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java @@ -0,0 +1,130 @@ +package org.briarproject.briar.android.hotspot; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ProgressBar; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.fragment.BaseFragment; + +import java.util.List; + +import javax.inject.Inject; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; + +import static android.content.Intent.ACTION_SEND; +import static android.content.Intent.EXTRA_STREAM; +import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; +import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; +import static android.os.Build.VERSION.SDK_INT; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static androidx.activity.result.contract.ActivityResultContracts.CreateDocument; +import static androidx.transition.TransitionManager.beginDelayedTransition; +import static org.briarproject.briar.android.AppModule.getAndroidComponent; +import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName; + + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class FallbackFragment extends BaseFragment { + + public static final String TAG = FallbackFragment.class.getName(); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private HotspotViewModel viewModel; + private final ActivityResultLauncher launcher = + registerForActivityResult(new CreateDocument(), + this::onDocumentCreated); + private Button fallbackButton; + private ProgressBar progressBar; + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + FragmentActivity activity = requireActivity(); + getAndroidComponent(activity).inject(this); + viewModel = new ViewModelProvider(activity, viewModelFactory) + .get(HotspotViewModel.class); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater + .inflate(R.layout.fragment_hotspot_save_apk, container, false); + } + + @Override + public void onViewCreated(View v, @Nullable Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + + fallbackButton = v.findViewById(R.id.fallbackButton); + progressBar = v.findViewById(R.id.progressBar); + fallbackButton.setOnClickListener(view -> { + beginDelayedTransition((ViewGroup) v); + fallbackButton.setVisibility(INVISIBLE); + progressBar.setVisibility(VISIBLE); + + if (SDK_INT >= 19) launcher.launch(getApkFileName()); + else viewModel.exportApk(); + }); + viewModel.getSavedApkToUri() + .observeEvent(this, uri -> shareUri(this, uri)); + } + + private void onDocumentCreated(@Nullable Uri uri) { + showButton(); + if (uri != null) viewModel.exportApk(uri); + } + + private void showButton() { + beginDelayedTransition((ViewGroup) requireView()); + fallbackButton.setVisibility(VISIBLE); + progressBar.setVisibility(INVISIBLE); + } + + static void shareUri(Fragment fragment, Uri uri) { + Intent i = new Intent(ACTION_SEND); + i.putExtra(EXTRA_STREAM, uri); + i.setType("*/*"); // gives us all sharing options + i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + Context ctx = fragment.requireContext(); + if (SDK_INT <= 19) { + // Workaround for Android bug: + // ctx.grantUriPermission also needed for Android 4 + List resInfoList = ctx.getPackageManager() + .queryIntentActivities(i, MATCH_DEFAULT_ONLY); + for (ResolveInfo resolveInfo : resInfoList) { + String packageName = resolveInfo.activityInfo.packageName; + ctx.grantUriPermission(packageName, uri, + FLAG_GRANT_READ_URI_PERMISSION); + } + } + fragment.startActivity(Intent.createChooser(i, null)); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java index 03b41379b..76c43c5d7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java @@ -9,7 +9,7 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; -import org.briarproject.briar.android.fragment.ErrorFragment; +import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.hotspot.HotspotState.HotspotError; import org.briarproject.briar.android.hotspot.HotspotState.HotspotStarted; @@ -26,7 +26,8 @@ import static org.briarproject.briar.api.android.AndroidNotificationManager.ACTI @MethodsNotNullByDefault @ParametersNotNullByDefault -public class HotspotActivity extends BriarActivity { +public class HotspotActivity extends BriarActivity + implements BaseFragmentListener { @Inject ViewModelProvider.Factory viewModelFactory; @@ -60,9 +61,8 @@ public class HotspotActivity extends BriarActivity { showFragment(fm, new HotspotFragment(), tag); } } else if (hotspotState instanceof HotspotError) { - String error = ((HotspotError) hotspotState).getError(); - Fragment f = ErrorFragment.newInstance(error); - showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG); + HotspotError error = ((HotspotError) hotspotState); + showErrorFragment(error.getError()); } }); @@ -74,6 +74,15 @@ public class HotspotActivity extends BriarActivity { } } + private void showErrorFragment(String error) { + FragmentManager fm = getSupportFragmentManager(); + String tag = HotspotErrorFragment.TAG; + if (fm.findFragmentByTag(tag) == null) { + Fragment f = HotspotErrorFragment.newInstance(error); + showFragment(fm, f, tag, false); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotErrorFragment.java new file mode 100644 index 000000000..eb0b73165 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotErrorFragment.java @@ -0,0 +1,78 @@ +package org.briarproject.briar.android.hotspot; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.fragment.BaseFragment; + +import javax.inject.Inject; + +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; + +import static org.briarproject.briar.android.util.UiUtils.triggerFeedback; + + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class HotspotErrorFragment extends BaseFragment { + + public static final String TAG = HotspotErrorFragment.class.getName(); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private static final String ERROR_MSG = "errorMessage"; + + public static HotspotErrorFragment newInstance(String message) { + HotspotErrorFragment f = new HotspotErrorFragment(); + Bundle args = new Bundle(); + args.putString(ERROR_MSG, message); + f.setArguments(args); + return f; + } + + private String errorMessage; + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = requireArguments(); + errorMessage = args.getString(ERROR_MSG); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + requireActivity().setTitle(R.string.error); + return inflater + .inflate(R.layout.fragment_hotspot_error, container, false); + } + + @Override + public void onViewCreated(View v, @Nullable Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + TextView msg = v.findViewById(R.id.errorMessageDetail); + msg.setText(errorMessage); + + Button feedbackButton = v.findViewById(R.id.feedbackButton); + feedbackButton.setOnClickListener( + button -> triggerFeedback(requireContext(), errorMessage)); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotHelpFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotHelpFragment.java index b0947f1da..aef52c5ac 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotHelpFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotHelpFragment.java @@ -1,41 +1,16 @@ package org.briarproject.briar.android.hotspot; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ProgressBar; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; -import java.util.List; - -import javax.inject.Inject; - -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts.CreateDocument; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.lifecycle.ViewModelProvider; - -import static android.content.Intent.ACTION_SEND; -import static android.content.Intent.EXTRA_STREAM; -import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; -import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; -import static android.os.Build.VERSION.SDK_INT; -import static android.view.View.INVISIBLE; -import static android.view.View.VISIBLE; -import static androidx.transition.TransitionManager.beginDelayedTransition; -import static org.briarproject.briar.android.AppModule.getAndroidComponent; -import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -43,25 +18,6 @@ public class HotspotHelpFragment extends Fragment { public final static String TAG = HotspotHelpFragment.class.getName(); - @Inject - ViewModelProvider.Factory viewModelFactory; - - private HotspotViewModel viewModel; - private final ActivityResultLauncher launcher = - registerForActivityResult(new CreateDocument(), - this::onDocumentCreated); - private Button button; - private ProgressBar progressBar; - - @Override - public void onAttach(Context context) { - super.onAttach(context); - FragmentActivity activity = requireActivity(); - getAndroidComponent(activity).inject(this); - viewModel = new ViewModelProvider(activity, viewModelFactory) - .get(HotspotViewModel.class); - } - @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -70,51 +26,4 @@ public class HotspotHelpFragment extends Fragment { .inflate(R.layout.fragment_hotspot_help, container, false); } - @Override - public void onViewCreated(View v, @Nullable Bundle savedInstanceState) { - super.onViewCreated(v, savedInstanceState); - button = v.findViewById(R.id.fallbackButton); - progressBar = v.findViewById(R.id.progressBar); - button.setOnClickListener(view -> { - beginDelayedTransition((ViewGroup) v); - button.setVisibility(INVISIBLE); - progressBar.setVisibility(VISIBLE); - - if (SDK_INT >= 19) launcher.launch(getApkFileName()); - else viewModel.exportApk(); - }); - viewModel.getSavedApkToUri().observeEvent(this, this::shareUri); - } - - private void onDocumentCreated(@Nullable Uri uri) { - showButton(); - if (uri != null) viewModel.exportApk(uri); - } - - private void shareUri(Uri uri) { - Intent i = new Intent(ACTION_SEND); - i.putExtra(EXTRA_STREAM, uri); - i.setType("*/*"); // gives us all sharing options - i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - Context ctx = requireContext(); - if (SDK_INT <= 19) { - // Workaround for Android bug: - // ctx.grantUriPermission also needed for Android 4 - List resInfoList = ctx.getPackageManager() - .queryIntentActivities(i, MATCH_DEFAULT_ONLY); - for (ResolveInfo resolveInfo : resInfoList) { - String packageName = resolveInfo.activityInfo.packageName; - ctx.grantUriPermission(packageName, uri, - FLAG_GRANT_READ_URI_PERMISSION); - } - } - startActivity(Intent.createChooser(i, null)); - } - - private void showButton() { - beginDelayedTransition((ViewGroup) requireView()); - button.setVisibility(VISIBLE); - progressBar.setVisibility(INVISIBLE); - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java index f231147e3..1fceb5133 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java @@ -42,6 +42,7 @@ import static android.os.Build.VERSION.SDK_INT; import static android.os.Environment.DIRECTORY_DOWNLOADS; import static android.os.Environment.getExternalStoragePublicDirectory; import static java.util.Objects.requireNonNull; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.briar.BuildConfig.DEBUG; @@ -144,7 +145,10 @@ class HotspotViewModel extends DbViewModel @Override public void onHotspotError(String error) { - state.setValue(new HotspotError(error)); + if (LOG.isLoggable(WARNING)) { + LOG.warning("Hotspot error: " + error); + } + state.postValue(new HotspotError(error)); ioExecutor.execute(webServerManager::stopWebServer); notificationManager.clearHotspotNotification(); } 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 740ebbddd..320f6d431 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 @@ -34,7 +34,7 @@ class BriarExceptionHandler implements UncaughtExceptionHandler { // activity runs in its own process, so we can kill the old one startDevReportActivity(app.getApplicationContext(), - CrashReportActivity.class, e, appStartTime, logKey); + CrashReportActivity.class, e, appStartTime, logKey, null); Process.killProcess(Process.myPid()); System.exit(10); } 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 e07b63d53..38dd7c545 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 @@ -33,6 +33,7 @@ import static java.util.Objects.requireNonNull; public class CrashReportActivity extends BaseActivity implements BaseFragmentListener { + public static final String EXTRA_INITIAL_COMMENT = "initialComment"; public static final String EXTRA_THROWABLE = "throwable"; public static final String EXTRA_APP_START_TIME = "appStartTime"; public static final String EXTRA_APP_LOGCAT = "logcat"; @@ -55,10 +56,11 @@ public class CrashReportActivity extends BaseActivity setContentView(R.layout.activity_dev_report); Intent intent = getIntent(); + String initialComment = intent.getStringExtra(EXTRA_INITIAL_COMMENT); Throwable t = (Throwable) intent.getSerializableExtra(EXTRA_THROWABLE); long appStartTime = intent.getLongExtra(EXTRA_APP_START_TIME, -1); byte[] logKey = intent.getByteArrayExtra(EXTRA_APP_LOGCAT); - viewModel.init(t, appStartTime, logKey); + viewModel.init(t, appStartTime, logKey, initialComment); viewModel.getShowReport().observeEvent(this, show -> { if (show) displayFragment(true); }); 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 2efd021e8..328ced375 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 @@ -78,6 +78,9 @@ public class ReportFormFragment extends BaseFragment { list = v.findViewById(R.id.list); progress = v.findViewById(R.id.progress_wheel); + if (viewModel.getInitialComment() != null) + userCommentView.setText(viewModel.getInitialComment()); + if (viewModel.isFeedback()) { includeDebugReport .setText(getString(R.string.include_debug_report_feedback)); 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 ef8679b7b..6e0a898b6 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 @@ -64,6 +64,8 @@ class ReportViewModel extends AndroidViewModel { private final MutableLiveEvent closeReport = new MutableLiveEvent<>(); private boolean isFeedback; + @Nullable + private String initialComment; @Inject ReportViewModel(@NonNull Application application, @@ -80,7 +82,8 @@ class ReportViewModel extends AndroidViewModel { } void init(@Nullable Throwable t, long appStartTime, - @Nullable byte[] logKey) { + @Nullable byte[] logKey, @Nullable String initialComment) { + this.initialComment = initialComment; isFeedback = t == null; if (reportData.getValue() == null) new SingleShotAndroidExecutor(() -> { String decryptedLogs; @@ -103,6 +106,11 @@ class ReportViewModel extends AndroidViewModel { }).start(); } + @Nullable + String getInitialComment() { + return initialComment; + } + boolean isFeedback() { return isFeedback; } @@ -140,7 +148,7 @@ class ReportViewModel extends AndroidViewModel { /** * The content of the report that will be loaded after - * {@link #init(Throwable, long, byte[])} was called. + * {@link #init(Throwable, long, byte[], String)} was called. */ LiveData getReportData() { return reportData; 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 ab03767f3..66378bf22 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 @@ -61,6 +61,7 @@ import androidx.core.util.Consumer; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; @@ -117,6 +118,7 @@ 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_LOGCAT; import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME; +import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_INITIAL_COMMENT; import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_THROWABLE; @MethodsNotNullByDefault @@ -143,13 +145,18 @@ public class UiUtils { public static void showFragment(FragmentManager fm, Fragment f, @Nullable String tag) { - fm.beginTransaction() + showFragment(fm, f, tag, true); + } + + public static void showFragment(FragmentManager fm, Fragment f, + @Nullable String tag, boolean addToBackStack) { + FragmentTransaction ta = fm.beginTransaction() .setCustomAnimations(R.anim.step_next_in, R.anim.step_previous_out, R.anim.step_previous_in, R.anim.step_next_out) - .replace(R.id.fragmentContainer, f, tag) - .addToBackStack(tag) - .commit(); + .replace(R.id.fragmentContainer, f, tag); + if (addToBackStack) ta.addToBackStack(tag); + ta.commit(); } public static String getContactDisplayName(Author author, @@ -428,17 +435,25 @@ public class UiUtils { } public static void triggerFeedback(Context ctx) { - startDevReportActivity(ctx, FeedbackActivity.class, null, null, null); + triggerFeedback(ctx, null); + } + + public static void triggerFeedback(Context ctx, + @Nullable String initialComment) { + startDevReportActivity(ctx, FeedbackActivity.class, null, null, null, + initialComment); } public static void startDevReportActivity(Context ctx, Class activity, @Nullable Throwable t, - @Nullable Long appStartTime, @Nullable byte[] logKey) { + @Nullable Long appStartTime, @Nullable byte[] logKey, @Nullable + String initialComment) { 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); dialogIntent.putExtra(EXTRA_APP_LOGCAT, logKey); + dialogIntent.putExtra(EXTRA_INITIAL_COMMENT, initialComment); ctx.startActivity(dialogIntent); } diff --git a/briar-android/src/main/res/layout/fragment_error.xml b/briar-android/src/main/res/layout/fragment_error.xml index 347d24b9d..ecb2bfe88 100644 --- a/briar-android/src/main/res/layout/fragment_error.xml +++ b/briar-android/src/main/res/layout/fragment_error.xml @@ -9,11 +9,7 @@ android:id="@+id/errorIcon" android:layout_width="128dp" android:layout_height="128dp" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_margin="8dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -25,11 +21,7 @@ android:id="@+id/errorTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginLeft="8dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="8dp" - android:layout_marginRight="8dp" + android:layout_margin="8dp" android:text="@string/sorry" android:textSize="@dimen/text_size_xlarge" app:layout_constraintEnd_toEndOf="parent" diff --git a/briar-android/src/main/res/layout/fragment_hotspot_error.xml b/briar-android/src/main/res/layout/fragment_hotspot_error.xml new file mode 100644 index 000000000..2e02edf41 --- /dev/null +++ b/briar-android/src/main/res/layout/fragment_hotspot_error.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + +