termux-app
225 строк · 9.6 Кб
1package com.termux.shared.interact;
2
3import android.Manifest;
4import android.app.Activity;
5import android.content.ActivityNotFoundException;
6import android.content.ClipData;
7import android.content.ClipboardManager;
8import android.content.Context;
9import android.content.Intent;
10import android.net.Uri;
11import android.os.Build;
12import android.os.Environment;
13
14import androidx.appcompat.app.AppCompatActivity;
15
16import com.termux.shared.R;
17import com.termux.shared.data.DataUtils;
18import com.termux.shared.data.IntentUtils;
19import com.termux.shared.file.FileUtils;
20import com.termux.shared.logger.Logger;
21import com.termux.shared.errors.Error;
22import com.termux.shared.android.PermissionUtils;
23
24import java.nio.charset.Charset;
25
26import javax.annotation.Nullable;
27
28public class ShareUtils {
29
30private static final String LOG_TAG = "ShareUtils";
31
32/**
33* Open the system app chooser that allows the user to select which app to send the intent.
34*
35* @param context The context for operations.
36* @param intent The intent that describes the choices that should be shown.
37* @param title The title for choose menu.
38*/
39public static void openSystemAppChooser(final Context context, final Intent intent, final String title) {
40if (context == null) return;
41
42final Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
43chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
44chooserIntent.putExtra(Intent.EXTRA_TITLE, title);
45chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
46try {
47context.startActivity(chooserIntent);
48} catch (Exception e) {
49Logger.logStackTraceWithMessage(LOG_TAG, "Failed to open system chooser for:\n" + IntentUtils.getIntentString(chooserIntent), e);
50}
51}
52
53/**
54* Share text.
55*
56* @param context The context for operations.
57* @param subject The subject for sharing.
58* @param text The text to share.
59*/
60public static void shareText(final Context context, final String subject, final String text) {
61shareText(context, subject, text, null);
62}
63
64/**
65* Share text.
66*
67* @param context The context for operations.
68* @param subject The subject for sharing.
69* @param text The text to share.
70* @param title The title for share menu.
71*/
72public static void shareText(final Context context, final String subject, final String text, @Nullable final String title) {
73if (context == null || text == null) return;
74
75final Intent shareTextIntent = new Intent(Intent.ACTION_SEND);
76shareTextIntent.setType("text/plain");
77shareTextIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
78shareTextIntent.putExtra(Intent.EXTRA_TEXT, DataUtils.getTruncatedCommandOutput(text, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, true, false, false));
79
80openSystemAppChooser(context, shareTextIntent, DataUtils.isNullOrEmpty(title) ? context.getString(R.string.title_share_with) : title);
81}
82
83
84
85/** Wrapper for {@link #copyTextToClipboard(Context, String, String, String)} with `null` `clipDataLabel` and `toastString`. */
86public static void copyTextToClipboard(Context context, final String text) {
87copyTextToClipboard(context, null, text, null);
88}
89
90/** Wrapper for {@link #copyTextToClipboard(Context, String, String, String)} with `null` `clipDataLabel`. */
91public static void copyTextToClipboard(Context context, final String text, final String toastString) {
92copyTextToClipboard(context, null, text, toastString);
93}
94
95/**
96* Copy the text to primary clip of the clipboard.
97*
98* @param context The context for operations.
99* @param clipDataLabel The label to show to the user describing the copied text.
100* @param text The text to copy.
101* @param toastString If this is not {@code null} or empty, then a toast is shown if copying to
102* clipboard is successful.
103*/
104public static void copyTextToClipboard(Context context, @Nullable final String clipDataLabel,
105final String text, final String toastString) {
106if (context == null || text == null) return;
107
108ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
109if (clipboardManager == null) return;
110
111clipboardManager.setPrimaryClip(ClipData.newPlainText(clipDataLabel,
112DataUtils.getTruncatedCommandOutput(text, DataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES,
113true, false, false)));
114
115if (toastString != null && !toastString.isEmpty())
116Logger.showToast(context, toastString, true);
117}
118
119
120
121/**
122* Wrapper for {@link #getTextFromClipboard(Context, boolean)} that returns primary text {@link String}
123* if its set and not empty.
124*/
125@Nullable
126public static String getTextStringFromClipboardIfSet(Context context, boolean coerceToText) {
127CharSequence textCharSequence = getTextFromClipboard(context, coerceToText);
128if (textCharSequence == null) return null;
129String textString = textCharSequence.toString();
130return !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
142public static CharSequence getTextFromClipboard(Context context, boolean coerceToText) {
143if (context == null) return null;
144
145ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
146if (clipboardManager == null) return null;
147
148ClipData clipData = clipboardManager.getPrimaryClip();
149if (clipData == null) return null;
150
151ClipData.Item clipItem = clipData.getItemAt(0);
152if (clipItem == null) return null;
153
154return coerceToText ? clipItem.coerceToText(context) : clipItem.getText();
155}
156
157
158
159/**
160* Open a url.
161*
162* @param context The context for operations.
163* @param url The url to open.
164*/
165public static void openUrl(final Context context, final String url) {
166if (context == null || url == null || url.isEmpty()) return;
167Uri uri = Uri.parse(url);
168Intent intent = new Intent(Intent.ACTION_VIEW, uri);
169try {
170context.startActivity(intent);
171} catch (ActivityNotFoundException e) {
172// If no activity found to handle intent, show system chooser
173openSystemAppChooser(context, intent, context.getString(R.string.title_open_url_with));
174} catch (Exception e) {
175Logger.logStackTraceWithMessage(LOG_TAG, "Failed to open url \"" + url + "\"", e);
176}
177}
178
179/**
180* Save a file at the path.
181*
182* If if path is under {@link Environment#getExternalStorageDirectory()}
183* or `/sdcard` and storage permission is missing, it will be requested if {@code context} is an
184* instance of {@link Activity} or {@link AppCompatActivity} and {@code storagePermissionRequestCode}
185* is `>=0` and the function will automatically return. The caller should call this function again
186* if user granted the permission.
187*
188* @param context The context for operations.
189* @param label The label for file.
190* @param filePath The path to save the file.
191* @param text The text to write to file.
192* @param showToast If set to {@code true}, then a toast is shown if saving to file is successful.
193* @param storagePermissionRequestCode The request code to use while asking for permission.
194*/
195public static void saveTextToFile(final Context context, final String label, final String filePath, final String text, final boolean showToast, final int storagePermissionRequestCode) {
196if (context == null || filePath == null || filePath.isEmpty() || text == null) return;
197
198// If path is under primary external storage directory, then check for missing permissions.
199if ((FileUtils.isPathInDirPath(filePath, Environment.getExternalStorageDirectory().getAbsolutePath(), true) ||
200FileUtils.isPathInDirPath(filePath, "/sdcard", true)) &&
201!PermissionUtils.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
202Logger.logErrorAndShowToast(context, LOG_TAG, context.getString(R.string.msg_storage_permission_not_granted));
203
204if (storagePermissionRequestCode >= 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
205if (context instanceof AppCompatActivity)
206PermissionUtils.requestPermission(((AppCompatActivity) context), Manifest.permission.WRITE_EXTERNAL_STORAGE, storagePermissionRequestCode);
207else if (context instanceof Activity)
208PermissionUtils.requestPermission(((Activity) context), Manifest.permission.WRITE_EXTERNAL_STORAGE, storagePermissionRequestCode);
209}
210
211return;
212}
213
214Error error = FileUtils.writeTextToFile(label, filePath,
215Charset.defaultCharset(), text, false);
216if (error != null) {
217Logger.logErrorExtended(LOG_TAG, error.toString());
218Logger.showToast(context, Error.getMinimalErrorString(error), true);
219} else {
220if (showToast)
221Logger.showToast(context, context.getString(R.string.msg_file_saved_successfully, label, filePath), true);
222}
223}
224
225}
226