diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e95702bc3..7a2a6e50b6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -233,4 +233,14 @@ + + + + + + + + diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 308d1f0b2b..89323e3cd3 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -18,6 +18,7 @@ import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; +import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -39,6 +40,7 @@ import com.termux.shared.data.IntentUtils; import com.termux.shared.android.PermissionUtils; import com.termux.shared.data.DataUtils; +import com.termux.shared.interact.ProcessTextUtils; import com.termux.shared.termux.TermuxConstants; import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY; import com.termux.app.activities.HelpActivity; @@ -68,6 +70,7 @@ import androidx.viewpager.widget.ViewPager; import java.util.Arrays; +import java.util.List; /** * A terminal emulator activity. @@ -189,6 +192,8 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo private static final int CONTEXT_MENU_HELP_ID = 7; private static final int CONTEXT_MENU_SETTINGS_ID = 8; private static final int CONTEXT_MENU_REPORT_ID = 9; + private static final int CONTEXT_MENU_SUBMENU_PROCESS_TEXT_ID = 11; + private static final int CONTEXT_MENU_LAUNCH_EXTERNAL_APP_PROCESS_TEXT_ID = 12; private static final String ARG_TERMINAL_TOOLBAR_TEXT_INPUT = "terminal_toolbar_text_input"; private static final String ARG_ACTIVITY_RECREATED = "activity_recreated"; @@ -642,8 +647,20 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn menu.add(Menu.NONE, CONTEXT_MENU_SELECT_URL_ID, Menu.NONE, R.string.action_select_url); menu.add(Menu.NONE, CONTEXT_MENU_SHARE_TRANSCRIPT_ID, Menu.NONE, R.string.action_share_transcript); - if (!DataUtils.isNullOrEmpty(mTerminalView.getStoredSelectedText())) + String selectedText = mTerminalView.getStoredSelectedText(); + if (!DataUtils.isNullOrEmpty(selectedText)) { menu.add(Menu.NONE, CONTEXT_MENU_SHARE_SELECTED_TEXT, Menu.NONE, R.string.action_share_selected_text); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List processTextActivities = ProcessTextUtils.getProcessTextActivities(this, selectedText); + if (!processTextActivities.isEmpty()) { + SubMenu processTextSubmenu = menu.addSubMenu(Menu.NONE, CONTEXT_MENU_SUBMENU_PROCESS_TEXT_ID, Menu.NONE, R.string.action_process_text); + for (ProcessTextUtils.ProcessTextActivityData processTextActivityData : processTextActivities) { + processTextSubmenu.add(Menu.NONE, CONTEXT_MENU_LAUNCH_EXTERNAL_APP_PROCESS_TEXT_ID, Menu.NONE, processTextActivityData.label) + .setIntent(processTextActivityData.intent); + } + } + } + } if (addAutoFillMenu) menu.add(Menu.NONE, CONTEXT_MENU_AUTOFILL_ID, Menu.NONE, R.string.action_autofill_password); menu.add(Menu.NONE, CONTEXT_MENU_RESET_TERMINAL_ID, Menu.NONE, R.string.action_reset_terminal); @@ -700,6 +717,9 @@ public boolean onContextItemSelected(MenuItem item) { case CONTEXT_MENU_REPORT_ID: mTermuxTerminalViewClient.reportIssueFromTranscript(); return true; + case CONTEXT_MENU_LAUNCH_EXTERNAL_APP_PROCESS_TEXT_ID: + ActivityUtils.startActivity(this, item.getIntent()); + return true; default: return super.onContextItemSelected(item); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 794d8df3e0..23a4d37f8a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -90,6 +90,8 @@ Generating Report Add termux debug info to report? + Select text processing app… + The &TERMUX_STYLING_APP_NAME; Plugin App is not installed. Install diff --git a/termux-shared/src/main/java/com/termux/shared/interact/ProcessTextUtils.java b/termux-shared/src/main/java/com/termux/shared/interact/ProcessTextUtils.java new file mode 100644 index 0000000000..3dcb92cb7c --- /dev/null +++ b/termux-shared/src/main/java/com/termux/shared/interact/ProcessTextUtils.java @@ -0,0 +1,69 @@ +package com.termux.shared.interact; + +import android.annotation.TargetApi; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Build; + +import java.util.ArrayList; +import java.util.List; + +public class ProcessTextUtils { + + /** + * Data required to interact with an activity that supports the PROCESS_TEXT intent. + */ + public static class ProcessTextActivityData { + /** + * The label of the external app activity. + */ + public final CharSequence label; + + /** + * The intent to launch the activity. + */ + public final Intent intent; + + private ProcessTextActivityData(CharSequence label, Intent intent) { + this.label = label; + this.intent = intent; + } + } + + /** + * Retrieve a list of activities (including outside of this app) that support the + * {@link Intent#ACTION_PROCESS_TEXT} intent action. For each item in the returned + * list, its Intent can be used to launch the activity with the given text. + * + * @param context The context for operations + * @param text The text to send in the Intents for the supported activities. + * @return a List of {@link ProcessTextActivityData} for supported activities. + */ + @TargetApi(Build.VERSION_CODES.M) + public static List getProcessTextActivities(Context context, String text) { + PackageManager packageManager = context.getPackageManager(); + Intent processTextIntent = new Intent(Intent.ACTION_PROCESS_TEXT); + processTextIntent.setType("text/plain"); + List activities = packageManager.queryIntentActivities(processTextIntent, PackageManager.MATCH_ALL); + List result = new ArrayList<>(); + for (ResolveInfo resolveInfo : activities) { + CharSequence label = resolveInfo.loadLabel(packageManager); + result.add(new ProcessTextActivityData(label, createProcessTextIntentForPackage(resolveInfo.activityInfo, text))); + } + return result; + } + + @TargetApi(Build.VERSION_CODES.M) + private static Intent createProcessTextIntentForPackage(ActivityInfo activityInfo, String text) { + Intent intent = new Intent(Intent.ACTION_PROCESS_TEXT); + intent.setComponent(new ComponentName(activityInfo.packageName, activityInfo.name)); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_PROCESS_TEXT, text); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } +}