termux-app/app/src/main/java/com/termux/app/TermuxOpenReceiver.java

194 lines
7.1 KiB
Java
Raw Normal View History

package com.termux.app;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxConstants;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
2019-01-11 20:19:06 +00:00
import androidx.annotation.NonNull;
public class TermuxOpenReceiver extends BroadcastReceiver {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
private static final String LOG_TAG = "TermuxOpenReceiver";
@Override
public void onReceive(Context context, Intent intent) {
final Uri data = intent.getData();
if (data == null) {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
Logger.logError(LOG_TAG, "termux-open: Called without intent data");
return;
}
final String filePath = data.getPath();
final String contentTypeExtra = intent.getStringExtra("content-type");
final boolean useChooser = intent.getBooleanExtra("chooser", false);
2017-02-27 23:42:07 +00:00
final String intentAction = intent.getAction() == null ? Intent.ACTION_VIEW : intent.getAction();
switch (intentAction) {
case Intent.ACTION_SEND:
case Intent.ACTION_VIEW:
// Ok.
break;
default:
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
Logger.logError(LOG_TAG, "Invalid action '" + intentAction + "', using 'view'");
2017-02-27 23:42:07 +00:00
break;
}
final boolean isExternalUrl = data.getScheme() != null && !data.getScheme().equals("file");
if (isExternalUrl) {
Intent urlIntent = new Intent(intentAction, data);
if (intentAction.equals(Intent.ACTION_SEND)) {
urlIntent.putExtra(Intent.EXTRA_TEXT, data.toString());
urlIntent.setData(null);
} else if (contentTypeExtra != null) {
urlIntent.setDataAndType(data, contentTypeExtra);
}
urlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(urlIntent);
} catch (ActivityNotFoundException e) {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
Logger.logError(LOG_TAG, "termux-open: No app handles the url " + data);
}
return;
}
final File fileToShare = new File(filePath);
if (!(fileToShare.isFile() && fileToShare.canRead())) {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
Logger.logError(LOG_TAG, "termux-open: Not a readable file: '" + fileToShare.getAbsolutePath() + "'");
return;
}
Intent sendIntent = new Intent();
sendIntent.setAction(intentAction);
sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
String contentTypeToUse;
if (contentTypeExtra == null) {
String fileName = fileToShare.getName();
int lastDotIndex = fileName.lastIndexOf('.');
2019-01-20 22:48:12 +00:00
String fileExtension = fileName.substring(lastDotIndex + 1);
MimeTypeMap mimeTypes = MimeTypeMap.getSingleton();
// Lower casing makes it work with e.g. "JPG":
contentTypeToUse = mimeTypes.getMimeTypeFromExtension(fileExtension.toLowerCase());
if (contentTypeToUse == null) contentTypeToUse = "application/octet-stream";
} else {
contentTypeToUse = contentTypeExtra;
}
Uri uriToShare = Uri.parse("content://" + TermuxConstants.TERMUX_FILE_SHARE_URI_AUTHORITY + fileToShare.getAbsolutePath());
if (Intent.ACTION_SEND.equals(intentAction)) {
sendIntent.putExtra(Intent.EXTRA_STREAM, uriToShare);
sendIntent.setType(contentTypeToUse);
} else {
sendIntent.setDataAndType(uriToShare, contentTypeToUse);
}
if (useChooser) {
sendIntent = Intent.createChooser(sendIntent, null).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
2017-02-27 23:42:07 +00:00
try {
context.startActivity(sendIntent);
} catch (ActivityNotFoundException e) {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
Logger.logError(LOG_TAG, "termux-open: No app handles the url " + data);
2017-02-27 23:42:07 +00:00
}
}
public static class ContentProvider extends android.content.ContentProvider {
@Override
public boolean onCreate() {
return true;
}
@Override
2017-03-06 00:47:08 +00:00
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
File file = new File(uri.getPath());
if (projection == null) {
projection = new String[]{
MediaStore.MediaColumns.DISPLAY_NAME,
MediaStore.MediaColumns.SIZE,
MediaStore.MediaColumns._ID
};
}
Object[] row = new Object[projection.length];
for (int i = 0; i < projection.length; i++) {
String column = projection[i];
Object value;
switch (column) {
case MediaStore.MediaColumns.DISPLAY_NAME:
value = file.getName();
break;
case MediaStore.MediaColumns.SIZE:
value = (int) file.length();
break;
case MediaStore.MediaColumns._ID:
value = 1;
break;
default:
value = null;
}
row[i] = value;
}
MatrixCursor cursor = new MatrixCursor(projection);
cursor.addRow(row);
return cursor;
}
@Override
2017-03-06 00:47:08 +00:00
public String getType(@NonNull Uri uri) {
return null;
}
@Override
2017-03-06 00:47:08 +00:00
public Uri insert(@NonNull Uri uri, ContentValues values) {
return null;
}
@Override
2017-03-06 00:47:08 +00:00
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
2017-03-06 00:47:08 +00:00
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
2017-03-06 00:47:08 +00:00
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
File file = new File(uri.getPath());
try {
String path = file.getCanonicalPath();
String storagePath = Environment.getExternalStorageDirectory().getCanonicalPath();
// See https://support.google.com/faqs/answer/7496913:
if (!(path.startsWith(TermuxConstants.TERMUX_FILES_DIR_PATH) || path.startsWith(storagePath))) {
throw new IllegalArgumentException("Invalid path: " + path);
}
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
}
}