2016-03-18 23:17:38 +00:00
|
|
|
package com.termux.filepicker;
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.provider.OpenableColumns;
|
|
|
|
import android.util.Patterns;
|
|
|
|
|
|
|
|
import com.termux.R;
|
2021-04-07 06:31:30 +00:00
|
|
|
import com.termux.shared.interact.DialogUtils;
|
|
|
|
import com.termux.shared.termux.TermuxConstants;
|
|
|
|
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
|
2016-03-18 23:17:38 +00:00
|
|
|
import com.termux.app.TermuxService;
|
2021-04-07 06:31:30 +00:00
|
|
|
import com.termux.shared.logger.Logger;
|
2016-03-18 23:17:38 +00:00
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
2020-01-05 00:02:13 +00:00
|
|
|
import java.util.regex.Pattern;
|
2016-03-18 23:17:38 +00:00
|
|
|
|
|
|
|
public class TermuxFileReceiverActivity extends Activity {
|
|
|
|
|
2021-03-11 15:11:59 +00:00
|
|
|
static final String TERMUX_RECEIVEDIR = TermuxConstants.TERMUX_FILES_DIR_PATH + "/home/downloads";
|
|
|
|
static final String EDITOR_PROGRAM = TermuxConstants.TERMUX_HOME_DIR_PATH + "/bin/termux-file-editor";
|
|
|
|
static final String URL_OPENER_PROGRAM = TermuxConstants.TERMUX_HOME_DIR_PATH + "/bin/termux-url-opener";
|
2016-03-18 23:17:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* If the activity should be finished when the name input dialog is dismissed. This is disabled
|
|
|
|
* before showing an error dialog, since the act of showing the error dialog will cause the
|
|
|
|
* name input dialog to be implicitly dismissed, and we do not want to finish the activity directly
|
|
|
|
* when showing the error dialog.
|
|
|
|
*/
|
2016-07-31 20:28:17 +00:00
|
|
|
boolean mFinishOnDismissNameDialog = true;
|
2016-03-18 23:17:38 +00:00
|
|
|
|
2021-03-13 11:49:29 +00:00
|
|
|
private static final String LOG_TAG = "TermuxFileReceiverActivity";
|
|
|
|
|
2020-01-05 00:02:13 +00:00
|
|
|
static boolean isSharedTextAnUrl(String sharedText) {
|
|
|
|
return Patterns.WEB_URL.matcher(sharedText).matches()
|
|
|
|
|| Pattern.matches("magnet:\\?xt=urn:btih:.*?", sharedText);
|
|
|
|
}
|
|
|
|
|
2016-03-18 23:17:38 +00:00
|
|
|
@Override
|
|
|
|
protected void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
|
|
|
|
final Intent intent = getIntent();
|
|
|
|
final String action = intent.getAction();
|
|
|
|
final String type = intent.getType();
|
|
|
|
final String scheme = intent.getScheme();
|
|
|
|
|
|
|
|
if (Intent.ACTION_SEND.equals(action) && type != null) {
|
|
|
|
final String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
|
|
final Uri sharedUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
|
|
|
|
|
|
|
if (sharedText != null) {
|
2020-01-05 00:02:13 +00:00
|
|
|
if (isSharedTextAnUrl(sharedText)) {
|
2016-03-18 23:17:38 +00:00
|
|
|
handleUrlAndFinish(sharedText);
|
|
|
|
} else {
|
|
|
|
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
|
|
|
if (subject == null) subject = intent.getStringExtra(Intent.EXTRA_TITLE);
|
|
|
|
if (subject != null) subject += ".txt";
|
|
|
|
promptNameAndSave(new ByteArrayInputStream(sharedText.getBytes(StandardCharsets.UTF_8)), subject);
|
|
|
|
}
|
|
|
|
} else if (sharedUri != null) {
|
|
|
|
handleContentUri(sharedUri, intent.getStringExtra(Intent.EXTRA_TITLE));
|
|
|
|
} else {
|
|
|
|
showErrorDialogAndQuit("Send action without content - nothing to save.");
|
|
|
|
}
|
2016-03-23 17:31:03 +00:00
|
|
|
} else if ("content".equals(scheme)) {
|
2016-03-18 23:17:38 +00:00
|
|
|
handleContentUri(intent.getData(), intent.getStringExtra(Intent.EXTRA_TITLE));
|
2016-03-23 17:31:03 +00:00
|
|
|
} else if ("file".equals(scheme)) {
|
2016-03-18 23:17:38 +00:00
|
|
|
// When e.g. clicking on a downloaded apk:
|
|
|
|
String path = intent.getData().getPath();
|
|
|
|
File file = new File(path);
|
|
|
|
try {
|
|
|
|
FileInputStream in = new FileInputStream(file);
|
|
|
|
promptNameAndSave(in, file.getName());
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
showErrorDialogAndQuit("Cannot open file: " + e.getMessage() + ".");
|
|
|
|
}
|
|
|
|
} else {
|
2016-03-23 17:31:03 +00:00
|
|
|
showErrorDialogAndQuit("Unable to receive any file or URL.");
|
2016-03-18 23:17:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void showErrorDialogAndQuit(String message) {
|
|
|
|
mFinishOnDismissNameDialog = false;
|
2018-09-28 22:49:05 +00:00
|
|
|
new AlertDialog.Builder(this).setMessage(message).setOnDismissListener(dialog -> finish()).setPositiveButton(android.R.string.ok, (dialog, which) -> finish()).show();
|
2016-03-18 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void handleContentUri(final Uri uri, String subjectFromIntent) {
|
|
|
|
try {
|
|
|
|
String attachmentFileName = null;
|
|
|
|
|
|
|
|
String[] projection = new String[]{OpenableColumns.DISPLAY_NAME};
|
|
|
|
try (Cursor c = getContentResolver().query(uri, projection, null, null, null)) {
|
|
|
|
if (c != null && c.moveToFirst()) {
|
|
|
|
final int fileNameColumnId = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
|
|
if (fileNameColumnId >= 0) attachmentFileName = c.getString(fileNameColumnId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attachmentFileName == null) attachmentFileName = subjectFromIntent;
|
|
|
|
|
|
|
|
InputStream in = getContentResolver().openInputStream(uri);
|
|
|
|
promptNameAndSave(in, attachmentFileName);
|
|
|
|
} catch (Exception e) {
|
|
|
|
showErrorDialogAndQuit("Unable to handle shared content:\n\n" + e.getMessage());
|
2021-03-13 11:49:29 +00:00
|
|
|
Logger.logStackTraceWithMessage(LOG_TAG, "handleContentUri(uri=" + uri + ") failed", e);
|
2016-03-18 23:17:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void promptNameAndSave(final InputStream in, final String attachmentFileName) {
|
2021-03-24 01:15:45 +00:00
|
|
|
DialogUtils.textInput(this, R.string.title_file_received, attachmentFileName, R.string.action_file_received_edit, text -> {
|
2018-09-28 22:49:05 +00:00
|
|
|
File outFile = saveStreamWithName(in, text);
|
|
|
|
if (outFile == null) return;
|
|
|
|
|
|
|
|
final File editorProgramFile = new File(EDITOR_PROGRAM);
|
|
|
|
if (!editorProgramFile.isFile()) {
|
|
|
|
showErrorDialogAndQuit("The following file does not exist:\n$HOME/bin/termux-file-editor\n\n"
|
|
|
|
+ "Create this file as a script or a symlink - it will be called with the received file as only argument.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do this for the user if necessary:
|
|
|
|
//noinspection ResultOfMethodCallIgnored
|
|
|
|
editorProgramFile.setExecutable(true);
|
|
|
|
|
|
|
|
final Uri scriptUri = new Uri.Builder().scheme("file").path(EDITOR_PROGRAM).build();
|
|
|
|
|
2021-03-08 10:09:22 +00:00
|
|
|
Intent executeIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE, scriptUri);
|
2018-09-28 22:49:05 +00:00
|
|
|
executeIntent.setClass(TermuxFileReceiverActivity.this, TermuxService.class);
|
2021-03-08 10:09:22 +00:00
|
|
|
executeIntent.putExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS, new String[]{outFile.getAbsolutePath()});
|
2018-09-28 22:49:05 +00:00
|
|
|
startService(executeIntent);
|
|
|
|
finish();
|
|
|
|
},
|
2021-03-24 01:15:45 +00:00
|
|
|
R.string.action_file_received_open_directory, text -> {
|
2018-09-28 22:49:05 +00:00
|
|
|
if (saveStreamWithName(in, text) == null) return;
|
|
|
|
|
2021-03-08 10:09:22 +00:00
|
|
|
Intent executeIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE);
|
|
|
|
executeIntent.putExtra(TERMUX_SERVICE.EXTRA_WORKDIR, TERMUX_RECEIVEDIR);
|
2018-09-28 22:49:05 +00:00
|
|
|
executeIntent.setClass(TermuxFileReceiverActivity.this, TermuxService.class);
|
|
|
|
startService(executeIntent);
|
|
|
|
finish();
|
2016-04-16 21:02:20 +00:00
|
|
|
},
|
2018-09-28 22:49:05 +00:00
|
|
|
android.R.string.cancel, text -> finish(), dialog -> {
|
|
|
|
if (mFinishOnDismissNameDialog) finish();
|
2016-04-16 21:02:20 +00:00
|
|
|
});
|
2016-03-18 23:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public File saveStreamWithName(InputStream in, String attachmentFileName) {
|
|
|
|
File receiveDir = new File(TERMUX_RECEIVEDIR);
|
|
|
|
if (!receiveDir.isDirectory() && !receiveDir.mkdirs()) {
|
|
|
|
showErrorDialogAndQuit("Cannot create directory: " + receiveDir.getAbsolutePath());
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
final File outFile = new File(receiveDir, attachmentFileName);
|
|
|
|
try (FileOutputStream f = new FileOutputStream(outFile)) {
|
|
|
|
byte[] buffer = new byte[4096];
|
|
|
|
int readBytes;
|
|
|
|
while ((readBytes = in.read(buffer)) > 0) {
|
|
|
|
f.write(buffer, 0, readBytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outFile;
|
|
|
|
} catch (IOException e) {
|
|
|
|
showErrorDialogAndQuit("Error saving file:\n\n" + e);
|
2021-03-13 11:49:29 +00:00
|
|
|
Logger.logStackTraceWithMessage(LOG_TAG, "Error saving file", e);
|
2016-03-18 23:17:38 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleUrlAndFinish(final String url) {
|
|
|
|
final File urlOpenerProgramFile = new File(URL_OPENER_PROGRAM);
|
|
|
|
if (!urlOpenerProgramFile.isFile()) {
|
|
|
|
showErrorDialogAndQuit("The following file does not exist:\n$HOME/bin/termux-url-opener\n\n"
|
|
|
|
+ "Create this file as a script or a symlink - it will be called with the shared URL as only argument.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do this for the user if necessary:
|
2016-04-22 00:17:41 +00:00
|
|
|
//noinspection ResultOfMethodCallIgnored
|
2016-03-18 23:17:38 +00:00
|
|
|
urlOpenerProgramFile.setExecutable(true);
|
|
|
|
|
|
|
|
final Uri urlOpenerProgramUri = new Uri.Builder().scheme("file").path(URL_OPENER_PROGRAM).build();
|
|
|
|
|
2021-03-08 10:09:22 +00:00
|
|
|
Intent executeIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE, urlOpenerProgramUri);
|
2016-03-18 23:17:38 +00:00
|
|
|
executeIntent.setClass(TermuxFileReceiverActivity.this, TermuxService.class);
|
2021-03-08 10:09:22 +00:00
|
|
|
executeIntent.putExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS, new String[]{url});
|
2016-03-18 23:17:38 +00:00
|
|
|
startService(executeIntent);
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|