Skip to content

Commit 0c14c29

Browse files
Changed: Use ShareUtils to copy and paste text and prevent potential NPE
The `copyTextToClipboard()` method has been updated to pass clip label when copying text to clipboard and `getTextFromClipboard()` and `getTextStringFromClipboardIfSet()` methods have been added to get current clipboard.
1 parent 63d035c commit 0c14c29

4 files changed

Lines changed: 78 additions & 30 deletions

File tree

app/src/main/java/com/termux/app/terminal/TermuxTerminalSessionActivityClient.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,16 @@ public void onSessionFinished(@NonNull TerminalSession finishedSession) {
183183
public void onCopyTextToClipboard(@NonNull TerminalSession session, String text) {
184184
if (!mActivity.isVisible()) return;
185185

186-
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
187-
clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(text)));
186+
ShareUtils.copyTextToClipboard(mActivity, text);
188187
}
189188

190189
@Override
191190
public void onPasteTextFromClipboard(@Nullable TerminalSession session) {
192191
if (!mActivity.isVisible()) return;
193192

194-
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
195-
ClipData clipData = clipboard.getPrimaryClip();
196-
if (clipData != null) {
197-
CharSequence paste = clipData.getItemAt(0).coerceToText(mActivity);
198-
if (!TextUtils.isEmpty(paste)) mActivity.getTerminalView().mEmulator.paste(paste.toString());
199-
}
193+
String text = ShareUtils.getTextStringFromClipboardIfSet(mActivity, true);
194+
if (text != null)
195+
mActivity.getTerminalView().mEmulator.paste(text);
200196
}
201197

202198
@Override

app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -702,9 +702,7 @@ public void showUrlSelection() {
702702
// Click to copy url to clipboard:
703703
final AlertDialog dialog = new AlertDialog.Builder(mActivity).setItems(urls, (di, which) -> {
704704
String url = (String) urls[which];
705-
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
706-
clipboard.setPrimaryClip(new ClipData(null, new String[]{"text/plain"}, new ClipData.Item(url)));
707-
Toast.makeText(mActivity, R.string.msg_select_url_copied_to_clipboard, Toast.LENGTH_LONG).show();
705+
ShareUtils.copyTextToClipboard(mActivity, url, mActivity.getString(R.string.msg_select_url_copied_to_clipboard));
708706
}).setTitle(R.string.title_select_url_dialog).create();
709707

710708
// Long press to open URL:
@@ -789,12 +787,9 @@ public void doPaste() {
789787
if (session == null) return;
790788
if (!session.isRunning()) return;
791789

792-
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
793-
ClipData clipData = clipboard.getPrimaryClip();
794-
if (clipData == null) return;
795-
CharSequence paste = clipData.getItemAt(0).coerceToText(mActivity);
796-
if (!TextUtils.isEmpty(paste))
797-
session.getEmulator().paste(paste.toString());
790+
String text = ShareUtils.getTextStringFromClipboardIfSet(mActivity, true);
791+
if (text != null)
792+
session.getEmulator().paste(text);
798793
}
799794

800795
}

terminal-view/src/main/java/com/termux/view/TerminalView.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,14 @@ public boolean onTouchEvent(MotionEvent event) {
566566
if (action == MotionEvent.ACTION_DOWN) showContextMenu();
567567
return true;
568568
} else if (event.isButtonPressed(MotionEvent.BUTTON_TERTIARY)) {
569-
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
570-
ClipData clipData = clipboard.getPrimaryClip();
569+
ClipboardManager clipboardManager = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
570+
ClipData clipData = clipboardManager.getPrimaryClip();
571571
if (clipData != null) {
572-
CharSequence paste = clipData.getItemAt(0).coerceToText(getContext());
573-
if (!TextUtils.isEmpty(paste)) mEmulator.paste(paste.toString());
572+
ClipData.Item clipItem = clipData.getItemAt(0);
573+
if (clipItem != null) {
574+
CharSequence text = clipItem.coerceToText(getContext());
575+
if (!TextUtils.isEmpty(text)) mEmulator.paste(text.toString());
576+
}
574577
}
575578
} else if (mEmulator.isMouseTrackingActive()) { // BUTTON_PRIMARY.
576579
switch (event.getAction()) {

termux-shared/src/main/java/com/termux/shared/interact/ShareUtils.java

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import android.os.Environment;
1313

1414
import androidx.appcompat.app.AppCompatActivity;
15-
import androidx.core.content.ContextCompat;
1615

1716
import com.termux.shared.R;
1817
import com.termux.shared.data.DataUtils;
@@ -81,27 +80,82 @@ public static void shareText(final Context context, final String subject, final
8180
openSystemAppChooser(context, shareTextIntent, DataUtils.isNullOrEmpty(title) ? context.getString(R.string.title_share_with) : title);
8281
}
8382

83+
84+
85+
/** Wrapper for {@link #copyTextToClipboard(Context, String, String, String)} with `null` `clipDataLabel` and `toastString`. */
86+
public static void copyTextToClipboard(Context context, final String text) {
87+
copyTextToClipboard(context, null, text, null);
88+
}
89+
90+
/** Wrapper for {@link #copyTextToClipboard(Context, String, String, String)} with `null` `clipDataLabel`. */
91+
public static void copyTextToClipboard(Context context, final String text, final String toastString) {
92+
copyTextToClipboard(context, null, text, toastString);
93+
}
94+
8495
/**
85-
* Copy the text to clipboard.
96+
* Copy the text to primary clip of the clipboard.
8697
*
8798
* @param context The context for operations.
99+
* @param clipDataLabel The label to show to the user describing the copied text.
88100
* @param text The text to copy.
89101
* @param toastString If this is not {@code null} or empty, then a toast is shown if copying to
90102
* clipboard is successful.
91103
*/
92-
public static void copyTextToClipboard(final Context context, final String text, final String toastString) {
104+
public static void copyTextToClipboard(Context context, @Nullable final String clipDataLabel,
105+
final String text, final String toastString) {
93106
if (context == null || text == null) return;
94107

95-
final ClipboardManager clipboardManager = ContextCompat.getSystemService(context, ClipboardManager.class);
108+
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
109+
if (clipboardManager == null) return;
96110

97-
if (clipboardManager != null) {
98-
clipboardManager.setPrimaryClip(ClipData.newPlainText(null, DataUtils.getTruncatedCommandOutput(text, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, true, false, false)));
99-
if (toastString != null && !toastString.isEmpty())
100-
Logger.showToast(context, toastString, true);
101-
}
111+
clipboardManager.setPrimaryClip(ClipData.newPlainText(clipDataLabel,
112+
DataUtils.getTruncatedCommandOutput(text, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES,
113+
true, false, false)));
114+
115+
if (toastString != null && !toastString.isEmpty())
116+
Logger.showToast(context, toastString, true);
102117
}
103118

119+
120+
104121
/**
122+
* Wrapper for {@link #getTextFromClipboard(Context, boolean)} that returns primary text {@link String}
123+
* if its set and not empty.
124+
*/
125+
@Nullable
126+
public static String getTextStringFromClipboardIfSet(Context context, boolean coerceToText) {
127+
CharSequence textCharSequence = getTextFromClipboard(context, coerceToText);
128+
if (textCharSequence == null) return null;
129+
String textString = textCharSequence.toString();
130+
return !textString.isEmpty() ? textString : null;
131+
}
132+
133+
/**
134+
* Get the text from primary clip of the clipboard.
135+
*
136+
* @param context The context for operations.
137+
* @param coerceToText Whether to call {@link ClipData.Item#coerceToText(Context)} to coerce
138+
* non-text data to text.
139+
* @return Returns the {@link CharSequence} of primary text. This will be `null` if failed to get it.
140+
*/
141+
@Nullable
142+
public static CharSequence getTextFromClipboard(Context context, boolean coerceToText) {
143+
if (context == null) return null;
144+
145+
ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
146+
if (clipboardManager == null) return null;
147+
148+
ClipData clipData = clipboardManager.getPrimaryClip();
149+
if (clipData == null) return null;
150+
151+
ClipData.Item clipItem = clipData.getItemAt(0);
152+
if (clipItem == null) return null;
153+
154+
return coerceToText ? clipItem.coerceToText(context) : clipItem.getText();
155+
}
156+
157+
158+
105159
* Open a url.
106160
*
107161
* @param context The context for operations.

0 commit comments

Comments
 (0)