From 2db1a01adb20416d259b06d592688c293d2a0112 Mon Sep 17 00:00:00 2001 From: Bans Date: Mon, 3 Jul 2023 20:04:14 +0530 Subject: [PATCH] background implemented --- .../java/com/termux/app/TermuxActivity.java | 148 ++++++++++++++++++ .../terminal/BackgroundOptions_dialog.java | 91 +++++++++++ .../termux/filepicker/FilePathFromDevice.java | 146 +++++++++++++++++ .../outline_background_rounded_corners.xml | 8 + .../res/drawable/sharp_landscape_white.xml | 11 ++ app/src/main/res/layout/activity_termux.xml | 27 ++++ .../res/layout/background_options_dialog.xml | 82 ++++++++++ 7 files changed, 513 insertions(+) create mode 100644 app/src/main/java/com/termux/app/terminal/BackgroundOptions_dialog.java create mode 100644 app/src/main/java/com/termux/filepicker/FilePathFromDevice.java create mode 100644 app/src/main/res/drawable/outline_background_rounded_corners.xml create mode 100644 app/src/main/res/drawable/sharp_landscape_white.xml create mode 100644 app/src/main/res/layout/background_options_dialog.xml diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index a2bb11e8c4..b23d130555 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -9,10 +9,15 @@ 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.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.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 void onCreate(Bundle savedInstanceState) { 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 void onSaveInstanceState(@NonNull Bundle savedInstanceState) { + /** + * 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 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten 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(); + } } } diff --git a/app/src/main/java/com/termux/app/terminal/BackgroundOptions_dialog.java b/app/src/main/java/com/termux/app/terminal/BackgroundOptions_dialog.java new file mode 100644 index 0000000000..62b428b2ef --- /dev/null +++ b/app/src/main/java/com/termux/app/terminal/BackgroundOptions_dialog.java @@ -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); + } + +} diff --git a/app/src/main/java/com/termux/filepicker/FilePathFromDevice.java b/app/src/main/java/com/termux/filepicker/FilePathFromDevice.java new file mode 100644 index 0000000000..726ad84035 --- /dev/null +++ b/app/src/main/java/com/termux/filepicker/FilePathFromDevice.java @@ -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()); + } +} diff --git a/app/src/main/res/drawable/outline_background_rounded_corners.xml b/app/src/main/res/drawable/outline_background_rounded_corners.xml new file mode 100644 index 0000000000..b7803833df --- /dev/null +++ b/app/src/main/res/drawable/outline_background_rounded_corners.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/drawable/sharp_landscape_white.xml b/app/src/main/res/drawable/sharp_landscape_white.xml new file mode 100644 index 0000000000..17c9bc0aef --- /dev/null +++ b/app/src/main/res/drawable/sharp_landscape_white.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/layout/activity_termux.xml b/app/src/main/res/layout/activity_termux.xml index 484990ff24..578805e87e 100644 --- a/app/src/main/res/layout/activity_termux.xml +++ b/app/src/main/res/layout/activity_termux.xml @@ -16,6 +16,19 @@ android:layout_marginVertical="0dp" android:orientation="vertical"> + + + + + + + + + diff --git a/app/src/main/res/layout/background_options_dialog.xml b/app/src/main/res/layout/background_options_dialog.xml new file mode 100644 index 0000000000..8bb84bde66 --- /dev/null +++ b/app/src/main/res/layout/background_options_dialog.xml @@ -0,0 +1,82 @@ + + + + + + + + + + +