1
0
mirror of https://github.com/termux/termux-app synced 2024-06-15 13:56:39 +00:00
This commit is contained in:
Sourabh Bans 2024-04-19 20:33:57 +05:00 committed by GitHub
commit 5fcf513d2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 513 additions and 0 deletions

View File

@ -9,10 +9,15 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Gravity;
@ -24,15 +29,18 @@ import android.view.WindowManager;
import android.view.autofill.AutofillManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.termux.R;
import com.termux.app.api.file.FileReceiverActivity;
import com.termux.app.terminal.BackgroundOptions_dialog;
import com.termux.app.terminal.TermuxActivityRootView;
import com.termux.app.terminal.TermuxTerminalSessionActivityClient;
import com.termux.app.terminal.io.TermuxTerminalExtraKeys;
import com.termux.filepicker.FilePathFromDevice;
import com.termux.shared.activities.ReportActivity;
import com.termux.shared.activity.ActivityUtils;
import com.termux.shared.activity.media.AppCompatActivityUtils;
@ -65,8 +73,15 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
/**
@ -195,6 +210,11 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
private static final String LOG_TAG = "TermuxActivity";
private ImageView background;
private View overlay;
private SharedPreferences prefs;
private final String BACKGROUND_FILE_NAME = "terminal_background.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
Logger.logDebug(LOG_TAG, "onCreate");
@ -242,6 +262,17 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
prefs = PreferenceManager.getDefaultSharedPreferences(TermuxActivity.this);
background = findViewById(R.id.bgImage);
overlay = findViewById(R.id.overlay);
// Load background on startup also
final File back_file = new File(getFilesDir(), BACKGROUND_FILE_NAME);
if(back_file.exists()){
setImage(back_file.getAbsolutePath());
}
setOverlay();
setTermuxTerminalViewAndClients();
setTerminalToolbarView(savedInstanceState);
@ -377,6 +408,94 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
/**
* Choose Terminal background image from Gallery
*/
public void choose_background(View view) {
new BackgroundOptions_dialog(TermuxActivity.this, new BackgroundOptions_dialog.Callback() {
@Override
public void onReset() {
final File back_file = new File(getFilesDir(), "terminal_background.jpg");
if(back_file.exists()){
boolean deleted = back_file.delete();
if(deleted){
background.setVisibility(View.GONE);
}
}
prefs.edit()
.putString("overlay", "#00000000")
.apply();
overlay.setVisibility(View.GONE);
}
@Override
public void onPick() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "Select Terminal Background"), 47);
}
@Override
public void onSave(String hex_overlay_color) {
if(hex_overlay_color==null || hex_overlay_color.length()<6){
Toast.makeText(TermuxActivity.this, "Not a valid color code", Toast.LENGTH_SHORT).show();
return;
}
if(!hex_overlay_color.startsWith("#")){
hex_overlay_color = "#"+hex_overlay_color;
}
try{
overlay.setBackgroundColor(Color.parseColor(hex_overlay_color));
overlay.setVisibility(View.VISIBLE);
prefs.edit()
.putString("overlay", hex_overlay_color)
.apply();
}catch (Exception ex){
ex.printStackTrace();
Toast.makeText(TermuxActivity.this, "Oops !"+ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}).show();
}
private void setImage(String selected){
try{
Bitmap bmp = BitmapFactory.decodeFile(selected);
background.setImageBitmap(bmp);
background.setVisibility(View.VISIBLE);
}catch (Exception ex){
ex.printStackTrace();
}
}
private void setOverlay(){
try{
String overlay_color = prefs.getString("overlay", "#00000000");
if(overlay_color!=null){
overlay.setBackgroundColor(Color.parseColor(overlay_color));
}
}catch (Exception ex){
ex.printStackTrace();
}
}
public void copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.flush();
out.close();
}
/**
@ -806,6 +925,35 @@ public final class TermuxActivity extends AppCompatActivity implements ServiceCo
Logger.logVerbose(LOG_TAG, "onActivityResult: requestCode: " + requestCode + ", resultCode: " + resultCode + ", data: " + IntentUtils.getIntentString(data));
if (requestCode == PermissionUtils.REQUEST_GRANT_STORAGE_PERMISSION) {
requestStoragePermission(true);
} else if (requestCode == 47) {
try {
if (resultCode == RESULT_OK) {
if (null == data) return;
Uri mImageCaptureUri = data.getData();
background.invalidate();
final File dir = getFilesDir();
if (!dir.exists()) {
dir.mkdirs();
}
final File back_file = new File(dir, BACKGROUND_FILE_NAME);
String selected;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
selected = FilePathFromDevice.loadFromGallery(TermuxActivity.this, mImageCaptureUri, back_file);
setImage(selected);
} else {
selected = FilePathFromDevice.getPath(TermuxActivity.this, mImageCaptureUri);
final File gallery_file = new File(selected);
if (!back_file.exists()) {
boolean created = back_file.createNewFile();
}
copy(gallery_file, back_file);
}
setImage(selected);
}
}catch (Exception ex){
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,91 @@
package com.termux.app.terminal;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.preference.PreferenceManager;
import com.termux.R;
import com.termux.app.TermuxActivity;
/**
* -- by srb.bans on 3/7/2023.
*/
public class BackgroundOptions_dialog {
private final Context context;
private final Callback callback;
public BackgroundOptions_dialog(Context ctx, Callback call) {
context = ctx;
callback = call;
}
public void show() {
LayoutInflater layoutInflaterAndroid = LayoutInflater.from(context);
View mView = layoutInflaterAndroid.inflate(R.layout.background_options_dialog, null);
AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(context, R.style.TermuxAlertDialogStyle);
alertDialogBuilderUserInput.setView(mView);
final AlertDialog alertDialogAndroid = alertDialogBuilderUserInput.create();
final EditText hex_code = mView.findViewById(R.id.hex_code);
final Button bt_reset = mView.findViewById(R.id.reset_background);
final Button bt_save = mView.findViewById(R.id.save);
final Button bt_pick = mView.findViewById(R.id.choose);
final View actionClose = mView.findViewById(R.id.action_close);
bt_save.setOnClickListener(view -> {
alertDialogAndroid.dismiss();
if (callback != null) {
String hex = "#00000000";
if (hex_code.length() > 0) {
hex = hex_code.getText().toString();
}
callback.onSave(hex);
}
});
bt_pick.setOnClickListener(view -> {
alertDialogAndroid.dismiss();
if (callback != null) callback.onPick();
});
bt_reset.setOnClickListener(view -> {
alertDialogAndroid.dismiss();
if (callback != null) callback.onReset();
});
actionClose.setOnClickListener(view -> {
alertDialogAndroid.dismiss();
});
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String overlay_color = prefs.getString("overlay", "#00000000");
if(overlay_color!=null){
hex_code.setText(overlay_color);
}
if (alertDialogAndroid.getWindow() != null)
alertDialogAndroid.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//Add animation to view
//BounceView.addAnimTo(alertDialogAndroid);
alertDialogAndroid.show();
}
public interface Callback {
void onReset();
void onPick();
void onSave(String hex_overlay_color);
}
}

View File

@ -0,0 +1,146 @@
package com.termux.filepicker;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* Created by abc on 7/14/2016.
*/
public final class FilePathFromDevice {
public static String loadFromGallery(final Context context, final Uri uri, File temp_file) {
final boolean is10 = Build.VERSION.SDK_INT > Build.VERSION_CODES.P;
if (is10) {
String path = null;
try {
if (temp_file.exists()) {
temp_file.delete();
}
temp_file.createNewFile();
ParcelFileDescriptor parcel = context.getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fd = parcel.getFileDescriptor();
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd);
parcel.close();
OutputStream os = new FileOutputStream(temp_file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.flush();
os.close();
path = temp_file.getAbsolutePath();
Log.e("copying done 10", " " + path);
} catch (Exception ex) {
Log.e("getPath", " " + ex.getMessage());
}
return path;
}
return null;
}
/**
* Get file path from URI
*
* @param context context of Activity
* @param uri uri of file
* @return path of given URI
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp" />
<stroke
android:width="1dp"
android:color="#E3E3E3" />
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M14,6l-3.75,5 2.85,3.8 -1.6,1.2C9.81,13.75 7,10 7,10l-6,8h22L14,6z" />
</vector>

View File

@ -16,6 +16,19 @@
android:layout_marginVertical="0dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/bgImage"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<View
android:id="@+id/overlay"
android:background="#B2000000"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
@ -59,6 +72,18 @@
android:background="@null"
android:contentDescription="@string/action_open_settings"
app:tint="?attr/termuxActivityDrawerImageTint" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/terminal_background"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="3dp"
android:adjustViewBounds="true"
android:background="?attr/selectableItemBackground"
android:layout_gravity="center"
android:src="@drawable/sharp_landscape_white"
android:onClick="choose_background" />
</LinearLayout>
<ListView
@ -91,6 +116,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/action_new_session" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:background="#232121"
tools:ignore="HardcodedText"
android:padding="20dp">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/choose"
android:textStyle="bold"
android:letterSpacing=".05"
android:textColor="#DADADA"
android:background="@drawable/outline_background_rounded_corners"
android:layout_margin="10dp"
android:paddingStart="15dp"
android:paddingTop="2dp"
android:paddingEnd="15dp"
android:paddingBottom="2dp"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Choose from gallery"/>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/hex_code"
android:textStyle="bold"
android:singleLine="false"
android:gravity="start"
android:textColor="#DADADA"
android:textColorHint="#838383"
android:padding="10dp"
android:letterSpacing=".03"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Put the overlay color hex/argb/rgb here"
tools:ignore="HardcodedText" />
<TableRow
android:layout_marginTop="30dp"
android:padding="10dp"
android:gravity="center|end"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/action_close"
android:textStyle="bold"
android:background="?android:attr/selectableItemBackground"
android:layout_margin="10dp"
android:letterSpacing=".1"
android:textColor="#DADADA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close" />
<Button
android:id="@+id/reset_background"
android:textStyle="bold"
android:background="?android:attr/selectableItemBackground"
android:layout_margin="10dp"
android:letterSpacing=".1"
android:textColor="#DADADA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reset" />
<Button
android:id="@+id/save"
android:textStyle="bold"
android:letterSpacing=".1"
android:background="?android:attr/selectableItemBackground"
android:layout_margin="10dp"
android:textColor="#DADADA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Save" />
</TableRow>
</LinearLayout>