From f857bf2968910387a599b7da468b8bc9f3aa2261 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Fri, 29 Oct 2021 00:58:48 +0500 Subject: [PATCH] Added: Add ActivityUtils.startActivity() and catch uncaught exceptions in TermuxActivity --- .../java/com/termux/app/TermuxActivity.java | 15 +++-- .../termux/shared/activity/ActivityUtils.java | 62 +++++++++++++++++-- .../shared/activity/ActivityUtilsErrno.java | 3 +- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 31883f19..9d930bc8 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -33,6 +33,7 @@ import android.widget.Toast; import com.termux.R; import com.termux.app.terminal.TermuxActivityRootView; import com.termux.shared.activities.ReportActivity; +import com.termux.shared.activity.ActivityUtils; import com.termux.shared.data.IntentUtils; import com.termux.shared.android.PermissionUtils; import com.termux.shared.termux.TermuxConstants; @@ -524,7 +525,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection private void setSettingsButtonView() { ImageButton settingsButton = findViewById(R.id.settings_button); settingsButton.setOnClickListener(v -> { - startActivity(new Intent(this, SettingsActivity.class)); + ActivityUtils.startActivity(this, new Intent(this, SettingsActivity.class)); }); } @@ -643,10 +644,10 @@ public final class TermuxActivity extends Activity implements ServiceConnection toggleKeepScreenOn(); return true; case CONTEXT_MENU_HELP_ID: - startActivity(new Intent(this, HelpActivity.class)); + ActivityUtils.startActivity(this, new Intent(this, HelpActivity.class)); return true; case CONTEXT_MENU_SETTINGS_ID: - startActivity(new Intent(this, SettingsActivity.class)); + ActivityUtils.startActivity(this, new Intent(this, SettingsActivity.class)); return true; case CONTEXT_MENU_REPORT_ID: mTermuxTerminalViewClient.reportIssueFromTranscript(); @@ -689,7 +690,9 @@ public final class TermuxActivity extends Activity implements ServiceConnection // The startActivity() call is not documented to throw IllegalArgumentException. // However, crash reporting shows that it sometimes does, so catch it here. new AlertDialog.Builder(this).setMessage(getString(R.string.error_styling_not_installed)) - .setPositiveButton(R.string.action_styling_install, (dialog, which) -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(TermuxConstants.TERMUX_STYLING_FDROID_PACKAGE_URL)))).setNegativeButton(android.R.string.cancel, null).show(); + .setPositiveButton(R.string.action_styling_install, + (dialog, which) -> ActivityUtils.startActivity(this, new Intent(Intent.ACTION_VIEW, Uri.parse(TermuxConstants.TERMUX_STYLING_FDROID_PACKAGE_URL)))) + .setNegativeButton(android.R.string.cancel, null).show(); } } private void toggleKeepScreenOn() { @@ -719,7 +722,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection * if targeting targetSdkVersion 30 (android 11) and running on sdk 30 (android 11) and higher. */ public void requestStoragePermission(boolean isPermissionCallback) { - new Thread() { + new Thread() { @Override public void run() { // Do not ask for permission again @@ -934,7 +937,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection public static void startTermuxActivity(@NonNull final Context context) { - context.startActivity(newInstance(context)); + ActivityUtils.startActivity(context, newInstance(context)); } public static Intent newInstance(@NonNull final Context context) { diff --git a/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtils.java b/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtils.java index d6b0a8de..89f2205e 100644 --- a/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtils.java @@ -17,6 +17,51 @@ public class ActivityUtils { private static final String LOG_TAG = "ActivityUtils"; + /** + * Wrapper for {@link #startActivity(Context, Intent, boolean, boolean)}. + */ + public static Error startActivity(@NonNull Context context, @NonNull Intent intent) { + return startActivity(context, intent, true, true); + } + + /** + * Start an {@link Activity}. + * + * @param context The context for operations. + * @param intent The {@link Intent} to send to start the activity. + * @param logErrorMessage If an error message should be logged if failed to start activity. + * @param showErrorMessage If an error message toast should be shown if failed to start activity + * in addition to logging a message. The {@code context} must not be + * {@code null}. + * @return Returns the {@code error} if starting activity was not successful, otherwise {@code null}. + + */ + public static Error startActivity(Context context, @NonNull Intent intent, + boolean logErrorMessage, boolean showErrorMessage) { + Error error; + String activityName = intent.getComponent() != null ? intent.getComponent().getClassName() : "Unknown"; + + if (context == null) { + error = ActivityUtilsErrno.ERRNO_STARTING_ACTIVITY_WITH_NULL_CONTEXT.getError(activityName); + if (logErrorMessage) + error.logErrorAndShowToast(null, LOG_TAG); + return error; + } + + try { + context.startActivity(intent); + } catch (Exception e) { + error = ActivityUtilsErrno.ERRNO_START_ACTIVITY_FAILED_WITH_EXCEPTION.getError(e, activityName, e.getMessage()); + if (logErrorMessage) + error.logErrorAndShowToast(showErrorMessage ? context : null, LOG_TAG); + return error; + } + + return null; + } + + + /** * Wrapper for {@link #startActivityForResult(Context, int, Intent, boolean, boolean, ActivityResultLauncher)}. */ @@ -44,22 +89,32 @@ public class ActivityUtils { * @param intent The {@link Intent} to send to start the activity. * @param logErrorMessage If an error message should be logged if failed to start activity. * @param showErrorMessage If an error message toast should be shown if failed to start activity - * in addition to logging a message. + * in addition to logging a message. The {@code context} must not be + * {@code null}. * @param activityResultLauncher The {@link ActivityResultLauncher} to use for start the * activity. If this is {@code null}, then - * {@link Activity#startActivity(Intent)} will be used instead. + * {@link Activity#startActivityForResult(Intent, int)} will be + * used instead. * Note that later is deprecated. * @return Returns the {@code error} if starting activity was not successful, otherwise {@code null}. */ - public static Error startActivityForResult(@NonNull Context context, int requestCode, @NonNull Intent intent, + public static Error startActivityForResult(Context context, int requestCode, @NonNull Intent intent, boolean logErrorMessage, boolean showErrorMessage, @Nullable ActivityResultLauncher activityResultLauncher) { Error error; + String activityName = intent.getComponent() != null ? intent.getComponent().getClassName() : "Unknown"; try { if (activityResultLauncher != null) { activityResultLauncher.launch(intent); } else { + if (context == null) { + error = ActivityUtilsErrno.ERRNO_STARTING_ACTIVITY_WITH_NULL_CONTEXT.getError(activityName); + if (logErrorMessage) + error.logErrorAndShowToast(null, LOG_TAG); + return error; + } + if (context instanceof AppCompatActivity) ((AppCompatActivity) context).startActivityForResult(intent, requestCode); else if (context instanceof Activity) @@ -72,7 +127,6 @@ public class ActivityUtils { } } } catch (Exception e) { - String activityName = intent.getComponent() != null ? intent.getComponent().getClassName() : "Unknown"; error = ActivityUtilsErrno.ERRNO_START_ACTIVITY_FOR_RESULT_FAILED_WITH_EXCEPTION.getError(e, activityName, e.getMessage()); if (logErrorMessage) error.logErrorAndShowToast(showErrorMessage ? context : null, LOG_TAG); diff --git a/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtilsErrno.java b/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtilsErrno.java index ef44a314..3c77cba9 100644 --- a/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtilsErrno.java +++ b/termux-shared/src/main/java/com/termux/shared/activity/ActivityUtilsErrno.java @@ -9,7 +9,8 @@ public class ActivityUtilsErrno extends Errno { /* Errors for starting activities (100-150) */ public static final Errno ERRNO_START_ACTIVITY_FAILED_WITH_EXCEPTION = new Errno(TYPE, 100, "Failed to start \"%1$s\" activity.\nException: %2$s"); - public static final Errno ERRNO_START_ACTIVITY_FOR_RESULT_FAILED_WITH_EXCEPTION = new Errno(TYPE, 100, "Failed to start \"%1$s\" activity for result.\nException: %2$s"); + public static final Errno ERRNO_START_ACTIVITY_FOR_RESULT_FAILED_WITH_EXCEPTION = new Errno(TYPE, 101, "Failed to start \"%1$s\" activity for result.\nException: %2$s"); + public static final Errno ERRNO_STARTING_ACTIVITY_WITH_NULL_CONTEXT = new Errno(TYPE, 102, "Cannot start \"%1$s\" activity with null Context"); ActivityUtilsErrno(final String type, final int code, final String message) {