Overwrites the file {@param iterations} times at once with random bytes and delete it
+ *
+ * @param file that should be deleted
+ * @param iterations how many times the file should be overwritten before it gets deleted
+ * @return if the file could be deleted
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ */
+ public static boolean deleteFileAllInOne(File file, int iterations) throws IOException, NoSuchAlgorithmException {
+ long fileLength = file.length() + 1 ;
+ for (int i=0; i 1000000000) {
+ int numOfByteArrays = (int) Math.ceil((double) fileLength / 1000000000);
+ for (int len=0; lenOverwrites the file {@param iterations} times at once with random bytes (minimal size {@param minFileSize}; maximal size {@param maxFileSize}) and delete it
Overwrites the file {@param iterations} times at once with random bytes (minimal size {@param minFileSize}; maximal size {@param maxFileSize}) and delete it
+ *
+ * @param file that should be deleted
+ * @param iterations how many times the file should be overwritten before it gets deleted
+ * @param minFileSize is the minimal file size for every {@param iterations}
+ * @param maxFileSize is the maximal file size for every {@param iterations}
+ * @return if the file could be deleted
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ */
+ public static boolean deleteFileAllInOne(File file, int iterations, long minFileSize, long maxFileSize) throws IOException, NoSuchAlgorithmException {
+ for (int i = 0; i < iterations; i++) {
+ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
+ if (maxFileSize > 1000000000) {
+ int numOfByteArrays = (int) Math.ceil((double) maxFileSize / 1000000000);
+ for (int len = 0; len < numOfByteArrays; len++) {
+ int newMaxFileSize = (int) maxFileSize / numOfByteArrays;
+ int newMinFileSize = 0;
+ if (minFileSize != 0) {
+ newMinFileSize = (int) minFileSize / numOfByteArrays;
+ }
+ byte[] randomBytes = new byte[new Random().nextInt(newMaxFileSize - newMinFileSize) + newMinFileSize];
+ SecureRandom.getInstance("SHA1PRNG").nextBytes(randomBytes);
+ bufferedOutputStream.write(randomBytes);
+ }
+ } else {
+ byte[] randomBytes = new byte[new Random().nextInt((int) maxFileSize - (int) minFileSize) + (int) minFileSize];
+ SecureRandom.getInstance("SHA1PRNG").nextBytes(randomBytes);
+ bufferedOutputStream.write(randomBytes);
+ }
+ bufferedOutputStream.flush();
+ bufferedOutputStream.close();
+ }
+
+ return file.delete();
+ }
+
+ /**
+ *
Overwrites the file {@param iterations} times line by line with random bytes and delete it
Overwrites the file {@param iterations} times line by line with random bytes and delete it
+ *
+ * @param file that should be deleted
+ * @param iterations how many times the file should be overwritten before it gets deleted
+ * @return if the file could be deleted
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ */
+ public static boolean deleteFileLineByLine(File file, int iterations) throws NoSuchAlgorithmException, IOException {
+ long fileLength = file.length() + 1 ;
+ for (int i=0; i 1000000000) {
+ int numOfByteArrays = (int) Math.ceil((double) fileLength / 1000000000);
+ for (int len=0; lenOverwrites the file {@param iterations} times line by line with random bytes (minimal size {@param minFileSize}; maximal size {@param maxFileSize}) and delete it
+ */
+ public static boolean deleteFileLineByLine(String filename, int iterations, long minFileSize, long maxFileSize) throws NoSuchAlgorithmException, IOException {
+ return deleteFileLineByLine(new File(filename), iterations, minFileSize, maxFileSize);
+ }
+
+ /**
+ *
Overwrites the file {@param iterations} times line by line with random bytes (minimal size {@param minFileSize}; maximal size {@param maxFileSize}) and delete it
+ *
+ * @param file that should be deleted
+ * @param iterations how many times the file should be overwritten before it gets deleted
+ * @param minFileSize is the minimal file size for every {@param iterations}
+ * @param maxFileSize is the maximal file size for every {@param iterations}
+ * @return if the file could be deleted
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ */
+ public static boolean deleteFileLineByLine(File file, int iterations, long minFileSize, long maxFileSize) throws NoSuchAlgorithmException, IOException {
+ for (int i=0; i 1000000000) {
+ int numOfByteArrays = (int) Math.ceil((double) maxFileSize / 1000000000);
+ for (int len=0; len idFileMap = Collections.synchronizedMap(new HashMap());
+
+ private static ArrayAdapter fileDeleteFileBoxAdapter;
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (requestCode == fileChooseReturnCode && resultCode == Activity.RESULT_OK) {
+ if (data.getClipData() != null) {
+ for (int i = 0; i < data.getClipData().getItemCount(); i++) {
+ try {
+ Uri uri = data.getClipData().getItemAt(i).getUri();
+ idFileMap.put(Utils.getFileName(this.getContext(), uri), uri);
+ fileDeleteFileBoxAdapter.add(Utils.getFileName(this.getContext(), uri));
+ fileDeleteFileBoxAdapter.notifyDataSetChanged();
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+ } else if (data.getData() != null) {
+ try {
+ Uri uri = data.getData();
+ idFileMap.put(Utils.getFileName(this.getContext(), uri), uri);
+ fileDeleteFileBoxAdapter.add(Utils.getFileName(this.getContext(), uri));
+ fileDeleteFileBoxAdapter.notifyDataSetChanged();
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case 0:
+ permission = grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults.length > 0;
+ }
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.secure_delete_files, container, false);
+
+ fragment = this;
+
+ fileDeleteFileBox = view.findViewById(R.id.fileDeleteFileBox);
+ fileDeleteFileBoxAdapter = new ArrayAdapter<>(this.getContext(), android.R.layout.simple_list_item_1);
+ fileDeleteFileBox.setAdapter(fileDeleteFileBoxAdapter);
+ fileDeleteIterationsEntry = view.findViewById(R.id.fileDeleteIterationsEntry);
+
+ DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ int bannerSize = AdSize.BANNER.getHeight();
+
+ ListView fileDeleteFileBox = view.findViewById(R.id.fileDeleteFileBox);
+ fileDeleteFileBox.getLayoutParams().height = Utils.percentOf(displayMetrics.heightPixels - bannerSize, 44);
+
+ int fileDeleteAdvancedTextWidth = view.findViewById(R.id.fileDeleteAdvancedText).getLayoutParams().width;
+ View fileDeleteSeparator1 = view.findViewById(R.id.fileDeleteSeparator1);
+ View fileDeleteSeparator2 = view.findViewById(R.id.fileDeleteSeparator2);
+ fileDeleteSeparator1.getLayoutParams().width = (displayMetrics.widthPixels - fileDeleteAdvancedTextWidth) / 2 - 10;
+ fileDeleteSeparator2.getLayoutParams().width = (displayMetrics.widthPixels - fileDeleteAdvancedTextWidth) / 2 - 10;
+
+ return view;
+ }
+
+ protected static void chooseFiles(View view) {
+ Intent i = new Intent(fragment.getContext(), FileDirChooser.class);
+ fragment.startActivity(i);
+ }
+
+ protected static void delete(View view) {
+ permission = Utils.askPermission(fragment, Manifest.permission.WRITE_EXTERNAL_STORAGE, 0);
+
+ if (permission) {
+ HashSet success = new HashSet<>();
+ int iterations;
+ try {
+ String iterationEntry = fileDeleteIterationsEntry.getText().toString();
+ if (iterationEntry.isEmpty()) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.empty_iterations), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ iterations = Integer.parseInt(iterationEntry);
+ } catch (NumberFormatException e) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.wrong_iterations), Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ for (Map.Entry entry: idFileMap.entrySet()) {
+ try {
+ File file = new File(Utils.getPath(view.getContext(), entry.getValue()));
+ if (file == null) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.no_file_path) + " " + entry.getKey(), Toast.LENGTH_LONG).show();
+ } else {
+ SecureDelete.deleteFileLineByLine(file, iterations);
+ while (file.isFile()) {
+ file.delete();
+ }
+ success.add(entry.getKey());
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ for (String name: success) {
+ idFileMap.remove(name);
+ fileDeleteFileBoxAdapter.remove(name);
+ }
+ fileDeleteFileBoxAdapter.notifyDataSetChanged();
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/TextEnDecrypt.java b/app/src/main/java/org/blueshard/android/cryptogx/TextEnDecrypt.java
new file mode 100755
index 0000000..33975a4
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/TextEnDecrypt.java
@@ -0,0 +1,171 @@
+package org.blueshard.android.cryptogx;
+
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import androidx.fragment.app.Fragment;
+
+import com.google.android.gms.ads.AdSize;
+import com.google.android.material.textfield.TextInputEditText;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+public class TextEnDecrypt extends Fragment {
+
+ private static TextInputEditText textEnDecryptKeyEntry;
+ private static TextInputEditText textEnDecryptSaltEntry;
+ private static EditText textEnDecryptDecryptedText;
+ private static EditText textEnDecryptEncryptedText;
+ private static Spinner textEnDecryptAlgorithms;
+
+ public static final String ARG = "textEnDecrypt";
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.text_en_decrypt, container, false);
+
+ textEnDecryptKeyEntry = view.findViewById(R.id.textEnDecryptKeyEntry);
+ textEnDecryptSaltEntry = view.findViewById(R.id.textEnDecryptSaltEntry);
+ textEnDecryptDecryptedText = view.findViewById(R.id.textEnDecryptDecryptedText);
+ textEnDecryptEncryptedText = view.findViewById(R.id.textEnDecryptEncryptedText);
+
+ DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ int bannerSize = AdSize.BANNER.getHeight();
+
+ EditText textEnDecryptDecryptedText = view.findViewById(R.id.textEnDecryptDecryptedText);
+ textEnDecryptDecryptedText.getLayoutParams().height = Utils.percentOf(displayMetrics.heightPixels - bannerSize, 21);
+
+ EditText textEnDecryptEncryptedText = view.findViewById(R.id.textEnDecryptEncryptedText);
+ textEnDecryptEncryptedText.getLayoutParams().height = Utils.percentOf(displayMetrics.heightPixels - bannerSize, 21);
+
+ int textEnDecryptAdvancedTextWidth = view.findViewById(R.id.textEnDecryptAdvancedText).getLayoutParams().width;
+ View textEnDecryptSeparator1 = view.findViewById(R.id.textEnDecryptSeparator1);
+ View textEnDecryptSeparator2 = view.findViewById(R.id.textEnDecryptSeparator2);
+ textEnDecryptSeparator1.getLayoutParams().width = (displayMetrics.widthPixels - textEnDecryptAdvancedTextWidth) / 2 - 10;
+ textEnDecryptSeparator2.getLayoutParams().width = (displayMetrics.widthPixels - textEnDecryptAdvancedTextWidth) / 2 - 10;
+
+ textEnDecryptAlgorithms = view.findViewById(R.id.textEnDecryptAlgorithms);
+ String[] algorithms = Utils.algorithms.keySet().toArray(new String[Utils.algorithms.size()]);
+ ArrayAdapter arrayAdapter = new ArrayAdapter(view.getContext(), android.R.layout.simple_spinner_item, algorithms);
+ textEnDecryptAlgorithms.setAdapter(arrayAdapter);
+
+ return view;
+ }
+
+ protected static void encrypt(View view) {
+ if (textEnDecryptKeyEntry.getText().toString().isEmpty()) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.empty_key), Toast.LENGTH_SHORT).show();
+ return;
+ }
+ try {
+ byte[] salt;
+ int lenght;
+
+ try {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 7));
+ } catch (NumberFormatException e) {
+ try {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 8));
+ } catch (NumberFormatException ex) {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 6));
+ }
+ }
+
+ if (textEnDecryptSaltEntry.getText().toString().isEmpty()) {
+ salt = new byte[16];
+ } else {
+ salt = textEnDecryptSaltEntry.getText().toString().getBytes(EnDecrypt.UTF_8);
+ }
+ EnDecrypt.AES encrypt = new EnDecrypt.AES(textEnDecryptKeyEntry.getText().toString(),
+ salt,
+ Utils.algorithms.get(textEnDecryptAlgorithms.getSelectedItem().toString()),
+ lenght);
+ String encryptedText = encrypt.encrypt(textEnDecryptDecryptedText.getText().toString());
+ textEnDecryptEncryptedText.setText(encryptedText);
+ } catch (InvalidKeySpecException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected static void decrypt(View view) {
+ if (textEnDecryptKeyEntry.getText().toString().isEmpty()) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.empty_key), Toast.LENGTH_SHORT).show();
+ return;
+ } else if (textEnDecryptEncryptedText.getText().toString().isEmpty()) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.empty_encrypted_text), Toast.LENGTH_LONG).show();
+ return;
+ }
+ try {
+ byte[] salt;
+ int lenght;
+
+ try {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 7));
+ } catch (NumberFormatException e) {
+ try {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 8));
+ } catch (NumberFormatException ex) {
+ lenght = Integer.parseInt(textEnDecryptAlgorithms.getSelectedItem().toString().substring(4, 6));
+ }
+ }
+
+ if (textEnDecryptSaltEntry.getText().toString().isEmpty()) {
+ salt = new byte[16];
+ } else {
+ salt = textEnDecryptSaltEntry.getText().toString().getBytes(EnDecrypt.UTF_8);
+ }
+ EnDecrypt.AES decrypt = new EnDecrypt.AES(textEnDecryptKeyEntry.getText().toString(),
+ salt,
+ Utils.algorithms.get(textEnDecryptAlgorithms.getSelectedItem().toString()),
+ lenght);
+ String encryptedText = decrypt.decrypt(textEnDecryptEncryptedText.getText().toString());
+ textEnDecryptDecryptedText.setText(encryptedText);
+ } catch (IllegalArgumentException e) {
+ Toast.makeText(view.getContext(), view.getResources().getString(R.string.empty_key), Toast.LENGTH_LONG).show();
+ } catch (InvalidKeySpecException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/Utils.java b/app/src/main/java/org/blueshard/android/cryptogx/Utils.java
new file mode 100755
index 0000000..0c2669d
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/Utils.java
@@ -0,0 +1,314 @@
+package org.blueshard.android.cryptogx;
+
+import android.Manifest;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.ThumbnailUtils;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+import android.util.Log;
+import android.util.Size;
+import android.webkit.MimeTypeMap;
+
+import androidx.fragment.app.Fragment;
+
+import java.io.File;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+public class Utils {
+
+ public static final int normalFile = 0;
+ public static final int imageFile = 1;
+ public static final int audioFile = 2;
+ public static final int videoFile = 3;
+
+ public static String UTF_8 = "UTF-8";
+ public static TreeMap algorithms = allAlgorithms();
+
+ private static TreeMap allAlgorithms() {
+ TreeMap return_map = new TreeMap<>();
+
+ int[] aesKeySizes = {128, 192, 256};
+
+ for (int i: aesKeySizes) {
+ return_map.put("AES-" + i, "AES");
+ }
+
+ return return_map;
+ }
+
+ protected static boolean askPermission(Fragment fragment, String permission, int requestCode) {
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ int permissionCheck = fragment.getContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
+ if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ fragment.requestPermissions(new String[]{permission}, requestCode);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public static String getFileName(Context context, Uri uri) {
+ String result = null;
+ if (uri.getScheme().equals("content")) {
+ Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ if (result == null) {
+ result = uri.getPath();
+ int cut = result.lastIndexOf('/');
+ if (cut != -1) {
+ result = result.substring(cut + 1);
+ }
+ }
+ return result;
+ }
+
+ public static String getPath(final Context context, final Uri uri) {
+
+ // check here to KITKAT or new version
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (GetPathUtils.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 (GetPathUtils.isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"),
+ Long.valueOf(id));
+
+ return GetPathUtils.getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (GetPathUtils.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 GetPathUtils.getDataColumn(context, contentUri, selection,
+ selectionArgs);
+ }
+ } else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+ // Return the remote address
+ if (GetPathUtils.isGooglePhotosUri(uri))
+ return uri.getLastPathSegment();
+
+ return GetPathUtils.getDataColumn(context, uri, null, null);
+ } else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ private static class GetPathUtils {
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ *
+ * @param context
+ * The context.
+ * @param uri
+ * The Uri to query.
+ * @param selection
+ * (Optional) Filter used in the query.
+ * @param selectionArgs
+ * (Optional) Selection arguments used in the query.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ 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;
+ }
+
+ /**
+ * @param uri
+ * The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ public static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri
+ .getAuthority());
+ }
+
+ /**
+ * @param uri
+ * The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ public static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri
+ .getAuthority());
+ }
+
+ /**
+ * @param uri
+ * The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri
+ .getAuthority());
+ }
+
+ /**
+ * @param uri
+ * The Uri to check.
+ * @return Whether the Uri authority is Google Photos.
+ */
+ public static boolean isGooglePhotosUri(Uri uri) {
+ return "com.google.android.apps.photos.content".equals(uri
+ .getAuthority());
+ }
+ }
+
+ public static int getTypeOfFile(String fname) {
+ if (!fname.contains(".")) {
+ return normalFile;
+ }
+ switch (fname.substring(fname.lastIndexOf(".") + 1)) {
+ case "bpm":
+ case "gif":
+ case "jpg":
+ case "png":
+ case "webp":
+ return imageFile;
+ case "heic":
+ case "heif":
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return imageFile;
+ } else {
+ return normalFile;
+ }
+
+ case "m4a":
+ case "acc":
+ case "flac":
+ case "gsm":
+ case "mid":
+ case "xmf":
+ case "mxmf":
+ case "rtttl":
+ case "rtx":
+ case "ota":
+ case "imy":
+ case "mp3":
+ case "wav":
+ case "ogg":
+ return audioFile;
+
+ case "3gp":
+ case "mp4":
+ case "ts":
+ case "webm":
+ case "mkv":
+ return videoFile;
+
+
+ default:
+ return normalFile;
+ }
+ }
+
+ public static int percentOf(int i, float percent) {
+ return (int) (i * (percent / 100));
+ }
+
+ public static class RecursivelyGetDirFile {
+
+ private TreeSet directories = new TreeSet<>();
+ private TreeSet files = new TreeSet<>();
+
+ RecursivelyGetDirFile(File file) {
+ getAll(file);
+ }
+
+ private void getAll(File startFile) {
+ for (File file: startFile.listFiles()) {
+ if (file.isFile()) {
+ files.add(file);
+ } else {
+ directories.add(file);
+ getAll(file);
+ }
+ }
+ }
+
+ public TreeSet getDirectories() {
+ return directories;
+ }
+
+ public TreeSet getFiles() {
+ return files;
+ }
+
+ }
+
+
+}
+
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirAdapter.java b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirAdapter.java
new file mode 100755
index 0000000..f26d18d
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirAdapter.java
@@ -0,0 +1,71 @@
+package org.blueshard.android.cryptogx.filedirchooser;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.blueshard.android.cryptogx.R;
+
+
+public class FileDirAdapter extends RecyclerView.Adapter {
+
+ private FileDirData[] dataSet;
+ private View.OnClickListener onClickListener;
+ private View.OnLongClickListener onLongClickListener;
+
+ public FileDirAdapter(FileDirData[] dataSet, View.OnClickListener onClickListener, View.OnLongClickListener onLongClickListener) {
+ this.dataSet = dataSet;
+ this.onClickListener = onClickListener;
+ this.onLongClickListener = onLongClickListener;
+ }
+
+ public class FileDirHolder extends RecyclerView.ViewHolder {
+
+ private final TextView textView;
+ private final ImageView imageView;
+
+ public FileDirHolder(View view) {
+ super(view);
+ this.textView = view.findViewById(R.id.fileDirText);
+ this.imageView = view.findViewById(R.id.fileDirImage);
+ }
+ }
+
+ @NonNull
+ @Override
+ public FileDirHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View chooserItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.file_dir_item, parent, false);
+
+ RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) chooserItem.getLayoutParams();
+ params.height = 200;
+ chooserItem.setLayoutParams(params);
+
+ chooserItem.setOnClickListener(onClickListener);
+ chooserItem.setOnLongClickListener(onLongClickListener);
+
+ return new FileDirHolder(chooserItem);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull FileDirHolder holder, int position) {
+ FileDirData data = dataSet[position];
+ if (data != null) {
+ holder.textView.setText(data.getFile().getName());
+ holder.imageView.setImageDrawable(data.getImage());
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return dataSet.length;
+ }
+
+ public FileDirData getData(int index) {
+ return dataSet[index];
+ }
+}
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirChooser.java b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirChooser.java
new file mode 100755
index 0000000..7cb52ed
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirChooser.java
@@ -0,0 +1,109 @@
+package org.blueshard.android.cryptogx.filedirchooser;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.View;
+
+import org.blueshard.android.cryptogx.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FileDirChooser extends AppCompatActivity {
+
+ private RecyclerView files;
+ private RecyclerView selectedFileDirs;
+ private FileDirAdapter filesAdapter;
+ private SelectedFileDirsAdapter selectedFileDirsAdapter;
+ private Context context = this;
+ private FileDirData[] dataSet;
+ private ArrayList selectedDataSet;
+
+ private boolean multipleMode = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_file_dir_chooser);
+
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fileDirFragment, new FileDirFragment());
+ transaction.addToBackStack(null);
+ transaction.commit();
+
+ final Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ File startDirectory;
+ if (extras != null) {
+ String directory = extras.getString("directory");
+ if (directory != null && !directory.equals("")) {
+ startDirectory = new File(directory);
+ } else {
+ startDirectory = Environment.getExternalStorageDirectory();
+ }
+
+ multipleMode = extras.getBoolean("multipleMode");
+
+ } else {
+ startDirectory = Environment.getExternalStorageDirectory();
+ }
+
+ dataSet = new FileDirData[startDirectory.listFiles().length];
+
+ filesInDir(startDirectory);
+
+ filesAdapter = new FileDirAdapter(dataSet, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ File file = filesAdapter.getData(files.getChildLayoutPosition(view)).getFile();
+ if (file.isDirectory()) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fileDirFragment, new FileDirFragment());
+ transaction.addToBackStack(null);
+ transaction.commit();
+ } else if (!multipleMode) {
+ View selectedFileDirs = findViewById(R.id.selectedFileDirs);
+ RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) selectedFileDirs.getLayoutParams();
+ params.height = 0;
+ selectedFileDirs.setLayoutParams(params);
+ }
+ }
+
+ }, new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ FileDirData data = filesAdapter.getData(files.getChildLayoutPosition(view));
+ if (multipleMode) {
+ selectedDataSet.add(data);
+ selectedFileDirsAdapter.notifyDataSetChanged();
+ return true;
+ } else if (data.getFile().isFile()) {
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ files = findViewById(R.id.files);
+ files.setAdapter(filesAdapter);
+ files.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+
+ selectedFileDirs = findViewById(R.id.selectedFileDirs);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirData.java b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirData.java
new file mode 100755
index 0000000..eecfeca
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirData.java
@@ -0,0 +1,26 @@
+package org.blueshard.android.cryptogx.filedirchooser;
+
+
+import android.graphics.drawable.Drawable;
+
+import java.io.File;
+
+public class FileDirData {
+
+ private final File file;
+ private final Drawable image;
+
+ public FileDirData(File file, Drawable image) {
+ this.file = file;
+ this.image = image;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public Drawable getImage() {
+ return image;
+ }
+
+}
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirFragment.java b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirFragment.java
new file mode 100755
index 0000000..e518fd7
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/FileDirFragment.java
@@ -0,0 +1,159 @@
+package org.blueshard.android.cryptogx.filedirchooser;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+
+import org.blueshard.android.cryptogx.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FileDirFragment extends Fragment {
+
+ private Context context;
+ private File directory;
+ private RecyclerView files;
+ private RecyclerView selectedFileDirs;
+ private FileDirAdapter filesAdapter;
+ private SelectedFileDirsAdapter selectedFileDirsAdapter;
+ private FileDirData[] dataSet;
+ private ArrayList selectedDataSet;
+
+ private boolean multipleMode = false;
+
+ public FileDirFragment(File directory) {
+ dataSet = new FileDirData[directory.listFiles().length];
+ this.directory = directory;
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ context = view.getContext();
+
+ RecyclerView files = (RecyclerView) view.findViewById(R.id.files);
+
+ filesInDir(directory);
+
+ filesAdapter = new FileDirAdapter(dataSet, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ File file = filesAdapter.getData(files.getChildLayoutPosition(view)).getFile();
+ if (file.isDirectory()) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fileDirFragment, new FileDirFragment());
+ transaction.addToBackStack(null);
+ transaction.commit();
+ } else if (!multipleMode) {
+ View selectedFileDirs = findViewById(R.id.selectedFileDirs);
+ RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) selectedFileDirs.getLayoutParams();
+ params.height = 0;
+ selectedFileDirs.setLayoutParams(params);
+ }
+ }
+
+ }, new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View view) {
+ FileDirData data = filesAdapter.getData(files.getChildLayoutPosition(view));
+ if (multipleMode) {
+ selectedDataSet.add(data);
+ selectedFileDirsAdapter.notifyDataSetChanged();
+ return true;
+ } else if (data.getFile().isFile()) {
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ files = view.findViewById(R.id.files);
+ files.setAdapter(filesAdapter);
+ files.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+
+ selectedFileDirs = new FileDirChooser().findViewById(R.id.selectedFileDirs);
+ }
+
+ private void filesInDir(File directory) {
+ final File[] files = directory.listFiles();
+
+ System.out.println(Arrays.toString(files));
+
+ if (files != null) {
+ Arrays.sort(files, new Comparator() {
+ @Override
+ public int compare(File object1, File object2) {
+ return object1.getName().compareToIgnoreCase(object2.getName());
+ }
+ });
+
+ final int cores;
+ if (files.length == 0) {
+ return;
+ } else if (files.length < Runtime.getRuntime().availableProcessors()) {
+ cores = files.length;
+ } else {
+ cores = (int) Math.ceil(files.length / Runtime.getRuntime().availableProcessors());
+ }
+ final AtomicInteger itemsPerThread = new AtomicInteger((int) Math.ceil(files.length / cores));
+ for (int core = 0; core < cores; core++) {
+ final int finalCore = core;
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ File file;
+ for (int i = itemsPerThread.get() * finalCore; i < i + itemsPerThread.get(); i++) {
+ try {
+ file = files[i];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return;
+ }
+ if (file.isDirectory()) {
+ dataSet[i] = new FileDirData(file, getResources().getDrawable(R.drawable.normal_folder));
+ continue;
+ } else {
+ try {
+ /*FileInputStream fis = new FileInputStream(file);
+ Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
+
+ Float width = new Float(imageBitmap.getWidth());
+ Float height = new Float(imageBitmap.getHeight());
+ Float ratio = width/height;
+ imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(64 * ratio), 64, false);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+ byte[] imageData = baos.toByteArray();
+ BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
+ dataSet[i] = new FileDirData(file, new BitmapDrawable(BitmapFactory.decodeByteArray(imageData, 0, imageData.length)));*/
+ dataSet[i] = new FileDirData(file, context.getResources().getDrawable(R.drawable.image_file));
+
+ } catch (Exception e) {
+ dataSet[i] = new FileDirData(file, getResources().getDrawable(R.drawable.normal_file));
+ }
+ }
+ }
+ }
+ };
+ thread.start();
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/SelectedFileDirsAdapter.java b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/SelectedFileDirsAdapter.java
new file mode 100755
index 0000000..fbc3019
--- /dev/null
+++ b/app/src/main/java/org/blueshard/android/cryptogx/filedirchooser/SelectedFileDirsAdapter.java
@@ -0,0 +1,72 @@
+package org.blueshard.android.cryptogx.filedirchooser;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.blueshard.android.cryptogx.R;
+
+import java.util.ArrayList;
+
+public class SelectedFileDirsAdapter extends RecyclerView.Adapter{
+
+ private ArrayList dataSet;
+ private View.OnClickListener onClickListener;
+ private View.OnLongClickListener onLongClickListener;
+
+ public SelectedFileDirsAdapter(ArrayList dataSet, View.OnClickListener onClickListener, View.OnLongClickListener onLongClickListener) {
+ this.dataSet = dataSet;
+ this.onClickListener = onClickListener;
+ this.onLongClickListener = onLongClickListener;
+ }
+
+ public class SelectedFileDirsHolder extends RecyclerView.ViewHolder {
+ public final TextView textView;
+ public final ImageView imageView;
+
+ public SelectedFileDirsHolder(View view) {
+ super(view);
+ this.textView = view.findViewById(R.id.fileImage);
+ this.imageView = view.findViewById(R.id.fileName);
+ }
+ }
+
+ @NonNull
+ @Override
+ public SelectedFileDirsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View selectedItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.selected_file_dirs_item, parent, false);
+
+ RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) selectedItem.getLayoutParams();
+ params.width = 120;
+ selectedItem.setLayoutParams(params);
+
+ selectedItem.setOnClickListener(onClickListener);
+ selectedItem.setOnLongClickListener(onLongClickListener);
+
+ return new SelectedFileDirsHolder(selectedItem);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull SelectedFileDirsHolder holder, int position) {
+ FileDirData data = dataSet.get(position);
+ if (data != null) {
+ holder.imageView.setImageDrawable(data.getImage());
+ holder.textView.setText(data.getFile().getName());
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return dataSet.size();
+ }
+
+ public FileDirData getData(int index) {
+ return dataSet.get(index);
+ }
+
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100755
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/audio_file.png b/app/src/main/res/drawable/audio_file.png
new file mode 100755
index 0000000..d6d475a
Binary files /dev/null and b/app/src/main/res/drawable/audio_file.png differ
diff --git a/app/src/main/res/drawable/cancel_button_style.xml b/app/src/main/res/drawable/cancel_button_style.xml
new file mode 100755
index 0000000..19e9dc6
--- /dev/null
+++ b/app/src/main/res/drawable/cancel_button_style.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/choose_files_style.xml b/app/src/main/res/drawable/choose_files_style.xml
new file mode 100755
index 0000000..a1197e3
--- /dev/null
+++ b/app/src/main/res/drawable/choose_files_style.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/decrypt_border_style.xml b/app/src/main/res/drawable/decrypt_border_style.xml
new file mode 100755
index 0000000..d85782d
--- /dev/null
+++ b/app/src/main/res/drawable/decrypt_border_style.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/encrypt_border_style.xml b/app/src/main/res/drawable/encrypt_border_style.xml
new file mode 100755
index 0000000..294f94f
--- /dev/null
+++ b/app/src/main/res/drawable/encrypt_border_style.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/file_box_style.xml b/app/src/main/res/drawable/file_box_style.xml
new file mode 100755
index 0000000..e67639f
--- /dev/null
+++ b/app/src/main/res/drawable/file_box_style.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100755
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/image_file.png b/app/src/main/res/drawable/image_file.png
new file mode 100755
index 0000000..0105051
Binary files /dev/null and b/app/src/main/res/drawable/image_file.png differ
diff --git a/app/src/main/res/drawable/normal_file.png b/app/src/main/res/drawable/normal_file.png
new file mode 100755
index 0000000..56c1d10
Binary files /dev/null and b/app/src/main/res/drawable/normal_file.png differ
diff --git a/app/src/main/res/drawable/normal_folder.png b/app/src/main/res/drawable/normal_folder.png
new file mode 100755
index 0000000..df43175
Binary files /dev/null and b/app/src/main/res/drawable/normal_folder.png differ
diff --git a/app/src/main/res/drawable/round_button_style.xml b/app/src/main/res/drawable/round_button_style.xml
new file mode 100755
index 0000000..8897fb2
--- /dev/null
+++ b/app/src/main/res/drawable/round_button_style.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/spinner_drop.png b/app/src/main/res/drawable/spinner_drop.png
new file mode 100755
index 0000000..9a889ea
Binary files /dev/null and b/app/src/main/res/drawable/spinner_drop.png differ
diff --git a/app/src/main/res/drawable/spinner_style.xml b/app/src/main/res/drawable/spinner_style.xml
new file mode 100755
index 0000000..016fe1f
--- /dev/null
+++ b/app/src/main/res/drawable/spinner_style.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/video_file.png b/app/src/main/res/drawable/video_file.png
new file mode 100755
index 0000000..1cbc94d
Binary files /dev/null and b/app/src/main/res/drawable/video_file.png differ
diff --git a/app/src/main/res/layout/activity_file_dir_chooser.xml b/app/src/main/res/layout/activity_file_dir_chooser.xml
new file mode 100755
index 0000000..b50c85e
--- /dev/null
+++ b/app/src/main/res/layout/activity_file_dir_chooser.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100755
index 0000000..a1ac3fe
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/file_dir_chooser.xml b/app/src/main/res/layout/file_dir_chooser.xml
new file mode 100755
index 0000000..93a3522
--- /dev/null
+++ b/app/src/main/res/layout/file_dir_chooser.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/file_dir_item.xml b/app/src/main/res/layout/file_dir_item.xml
new file mode 100755
index 0000000..fb95ced
--- /dev/null
+++ b/app/src/main/res/layout/file_dir_item.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/file_en_decrypt.xml b/app/src/main/res/layout/file_en_decrypt.xml
new file mode 100755
index 0000000..7741899
--- /dev/null
+++ b/app/src/main/res/layout/file_en_decrypt.xml
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/secure_delete_files.xml b/app/src/main/res/layout/secure_delete_files.xml
new file mode 100755
index 0000000..c57e6d2
--- /dev/null
+++ b/app/src/main/res/layout/secure_delete_files.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/selected_file_dirs_item.xml b/app/src/main/res/layout/selected_file_dirs_item.xml
new file mode 100755
index 0000000..471dd97
--- /dev/null
+++ b/app/src/main/res/layout/selected_file_dirs_item.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/text_en_decrypt.xml b/app/src/main/res/layout/text_en_decrypt.xml
new file mode 100755
index 0000000..540e05e
--- /dev/null
+++ b/app/src/main/res/layout/text_en_decrypt.xml
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100755
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100755
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100755
index 0000000..a571e60
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100755
index 0000000..61da551
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/cryptogx_icon_android.png b/app/src/main/res/mipmap-mdpi/cryptogx_icon_android.png
new file mode 100755
index 0000000..4e3077d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/cryptogx_icon_android.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100755
index 0000000..c41dd28
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100755
index 0000000..db5080a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..6dba46d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100755
index 0000000..da31a87
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..15ac681
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100755
index 0000000..b216f2d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100755
index 0000000..f25a419
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100755
index 0000000..e96783c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
new file mode 100755
index 0000000..58963b6
--- /dev/null
+++ b/app/src/main/res/values-de/strings.xml
@@ -0,0 +1,27 @@
+
+
+ Text ent- / verschlüsseln
+ Dateien ent- / verschlüsseln
+ Dateien sicher löschen
+ Schlüssel
+ Schlüssel anzeigen
+ Verschlüsselter Text
+ Entschlüsselter Text
+ Verschlüsseln
+ Entschlüsseln
+ Erweitert
+ Algorithmus
+ Salt
+ Dateien auswählen...
+ Stoppen
+ Dateien auswählen...
+ Wiederholungen
+ Löschen
+ Leerer Schlüssel wurde gegeben
+ Leerer verschlüsselter Text wurde gegeben
+ Ausgabe Datei
+ "Ordner konnte nicht erstellt werden: "
+ Pfad der Datei konnte nicht gefunden werden:
+ Keine Wiederholungen gegeben
+ Falsche Wiederholungen gegeben
+
\ No newline at end of file
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
new file mode 100755
index 0000000..7f44f47
--- /dev/null
+++ b/app/src/main/res/values-en/strings.xml
@@ -0,0 +1,26 @@
+
+ En- / decrypt text
+ En- / decrypt files
+ Secure delete files
+ Key
+ Show key
+ Encrypted text
+ Decrypted text
+ Encrypt
+ Decrypt
+ Advanced
+ Algorithm
+ Salt
+ Choose files...
+ Cancel
+ Choose files...
+ Iterations
+ Delete
+ Empty key is given
+ Empty encrypted text is given
+ Output file
+ Couldn\'t create folder:
+ Couldn\'t get path from file:
+ No iterations are given
+ Wrong iterations are given
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100755
index 0000000..030098f
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #6200EE
+ #3700B3
+ #03DAC5
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100755
index 0000000..4b2663b
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,33 @@
+
+
+ cryptoGX
+
+
+
+ ca-app-pub-8690297592769912~2837426184
+
+ En- / decrypt text
+ En- / decrypt files
+ Secure delete files
+ Key
+ Show key
+ Encrypted text
+ Decrypted text
+ Encrypt
+ Decrypt
+ Advanced
+ Algortihm
+ Salt
+ Choose files...
+ Cancel
+ Choose files...
+ Iterations
+ Delete
+ Empty key is given
+ Empty encrypted text is given
+ Output file
+ Couldn\'t create folder:
+ Couldn\'t get path from file:
+ Empty iterations are given
+ Wrong iterations are given
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100755
index 0000000..fc847ff
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/org/blueshard/android/cryptogx/ExampleUnitTest.java b/app/src/test/java/org/blueshard/android/cryptogx/ExampleUnitTest.java
new file mode 100755
index 0000000..8337721
--- /dev/null
+++ b/app/src/test/java/org/blueshard/android/cryptogx/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package org.blueshard.android.cryptogx;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100755
index 0000000..be0f7ca
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,29 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.0.0'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/cryptoGX_mobile_key.jks b/cryptoGX_mobile_key.jks
new file mode 100755
index 0000000..928edeb
Binary files /dev/null and b/cryptoGX_mobile_key.jks differ
diff --git a/gradle.properties b/gradle.properties
new file mode 100755
index 0000000..199d16e
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100755
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100755
index 0000000..134ba26
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sun Jun 28 20:31:48 CEST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100755
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/password b/password
new file mode 100755
index 0000000..0829fed
--- /dev/null
+++ b/password
@@ -0,0 +1,2 @@
+Key store password: Bv=D+P24a(\W{pNzhjj&
+Key password: %jMB97_xN'7n[wGP5S~b
diff --git a/settings.gradle b/settings.gradle
new file mode 100755
index 0000000..1f8b80a
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name='cryptoGX'
+include ':app'