From bafd7914b47160c149265ee7bae2e7781f1b47c5 Mon Sep 17 00:00:00 2001 From: An Bui <91354810+AnBui2004@users.noreply.github.com> Date: Sat, 10 Jan 2026 21:04:32 +0700 Subject: [PATCH] 3.6.7 - Added choose location save exported rom. - Bugs fixed. --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 4 +- .../com/vectras/vm/ExportRomActivity.java | 169 +- .../main/java/com/vectras/vm/Minitools.java | 26 - .../main/java/com/vectras/vm/VMManager.java | 5 +- .../QemuParamsEditorActivity.java | 3 +- .../vm/{ => creator}/SetArchActivity.java | 304 +-- .../vectras/vm/creator/VMCreatorActivity.java | 8 +- .../vectras/vm/creator/VMCreatorSelector.java | 27 +- .../com/vectras/vm/main/MainActivity.java | 8 +- .../vm/main/core/RomOptionsDialog.java | 2 +- .../vm/setupwizard/SetupWizard2Activity.java | 11 +- .../com/vectras/vm/utils/DialogUtils.java | 7 +- .../java/com/vectras/vm/utils/FileUtils.java | 1638 +++++++++-------- .../com/vectras/vm/utils/IntentUtils.java | 44 + .../java/com/vectras/vm/utils/ZipUtils.java | 143 +- .../com/vectras/vm/view/GithubUserView.java | 16 +- .../main/java/com/vectras/vterm/Terminal.java | 77 +- .../layout/activity_qemu_params_editor.xml | 2 +- .../layout/dialog_list_selector_layout.xml | 47 + app/src/main/res/layout/recycler_view.xml | 9 - .../simple_layout_list_view_with_check.xml | 18 +- app/src/main/res/values/strings.xml | 2 + web/data/UpdateConfig.json | 8 +- 24 files changed, 1333 insertions(+), 1249 deletions(-) rename app/src/main/java/com/vectras/vm/{ => creator}/QemuParamsEditorActivity.java (96%) rename app/src/main/java/com/vectras/vm/{ => creator}/SetArchActivity.java (96%) create mode 100644 app/src/main/java/com/vectras/vm/utils/IntentUtils.java create mode 100644 app/src/main/res/layout/dialog_list_selector_layout.xml delete mode 100644 app/src/main/res/layout/recycler_view.xml diff --git a/app/build.gradle b/app/build.gradle index 5e65ccc..9289d89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi - versionCode 70 - versionName "3.6.6" + versionCode 71 + versionName "3.6.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4d5446d..3eb2f99 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -130,7 +130,7 @@ android:exported="true" android:hardwareAccelerated="true" /> diff --git a/app/src/main/java/com/vectras/vm/ExportRomActivity.java b/app/src/main/java/com/vectras/vm/ExportRomActivity.java index 20bb87f..13492fd 100644 --- a/app/src/main/java/com/vectras/vm/ExportRomActivity.java +++ b/app/src/main/java/com/vectras/vm/ExportRomActivity.java @@ -5,19 +5,22 @@ import android.app.Activity; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import androidx.activity.OnBackPressedCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import com.vectras.vm.databinding.ActivityExportRomBinding; +import com.vectras.vm.main.vms.DataMainRoms; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.PackageUtils; @@ -31,16 +34,12 @@ import java.util.Objects; public class ExportRomActivity extends AppCompatActivity { + private final String TAG = "ExportRomActivity"; ActivityExportRomBinding binding; - public static int pendingPosition = 0; - public static HashMap mapForGetData = new HashMap<>(); - public static ArrayList> listmapForGetData = new ArrayList<>(); private SharedPreferences data; - public String getRomPath = ""; - public String iconfile = ""; - public String diskfile = ""; - public String cdromfile = ""; private boolean isExporting = false; + private ActivityResultLauncher folderPicker; + private DataMainRoms current; @Override @@ -59,7 +58,7 @@ public class ExportRomActivity extends AppCompatActivity { binding.edContent.setEnabled(false); binding.edAuthor.setEnabled(true); binding.edContent.setEnabled(true); - startCreate(); + folderPicker.launch(current.itemName + ".cvbi"); }); data = getSharedPreferences("data", Activity.MODE_PRIVATE); @@ -67,6 +66,16 @@ public class ExportRomActivity extends AppCompatActivity { binding.edAuthor.setText(data.getString("author", "")); binding.edContent.setText(data.getString("desc", "")); + current = VMManager.getVMConfig(getIntent().getIntExtra("POS", 0)); + + folderPicker = registerForActivityResult( + new ActivityResultContracts.CreateDocument("application/octet-stream"), + uri -> { + if (uri != null) { + startCreate(uri); + } + }); + getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { @@ -87,8 +96,9 @@ public class ExportRomActivity extends AppCompatActivity { } @SuppressLint("SetTextI18n") - private void startCreate() { - File vDir = new File(AppConfig.cvbiFolder); + private void startCreate(Uri uri) { + String cvbiFolder = Objects.requireNonNull(getExternalCacheDir()).getAbsolutePath() + "/cvbi/"; + File vDir = new File(cvbiFolder); if (!vDir.exists()) { if (!vDir.mkdirs()) { DialogUtils.oneDialog(this, @@ -104,90 +114,53 @@ public class ExportRomActivity extends AppCompatActivity { } } - listmapForGetData.clear(); - mapForGetData.clear(); + String getRomPath = AppConfig.vmFolder + current.vmID + "/"; + HashMap vmConfigMap = new HashMap<>(); - listmapForGetData = new Gson().fromJson(FileUtils.readAFile(AppConfig.romsdatajson), new TypeToken>>() { - }.getType()); + vmConfigMap.put("title", current.itemName); - getRomPath = AppConfig.vmFolder + Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("vmID")) + "/"; + if (FileUtils.isFileExists(current.itemIcon)) { + vmConfigMap.put("icon", new File(Objects.requireNonNull(Uri.parse(current.itemIcon).getPath())).getName()); + } else { + vmConfigMap.put("icon", current.itemIcon); + } - if (listmapForGetData.get(pendingPosition).containsKey("imgName")) { - mapForGetData.put("title", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgName")).toString()); + if (FileUtils.isFileExists(current.itemPath)) { + vmConfigMap.put("drive", new File(Objects.requireNonNull(Uri.parse(current.itemPath).getPath())).getName()); } else { - mapForGetData.put("title", ""); + vmConfigMap.put("drive", VMManager.quickScanDiskFileInFolder(getRomPath)); } - if (listmapForGetData.get(pendingPosition).containsKey("imgIcon")) { - iconfile = Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgIcon")).toString(); - try { - mapForGetData.put("icon", Uri.parse(Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgIcon")).toString()).getLastPathSegment()); - } catch (Exception _e) { - mapForGetData.put("icon", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgIcon")).toString()); - } + + if (FileUtils.isFileExists(current.imgCdrom)) { + vmConfigMap.put("cdrom", new File(Objects.requireNonNull(Uri.parse(current.imgCdrom).getPath())).getName()); } else { - mapForGetData.put("icon", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("imgPath")) { - if (Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgPath")).toString().isEmpty()) { - diskfile = VMManager.quickScanDiskFileInFolder(getRomPath); - } else { - diskfile = Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgPath")).toString(); - } - mapForGetData.put("drive", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgPath")).toString().replaceAll(getRomPath, "")); - } else { - diskfile = VMManager.quickScanDiskFileInFolder(getRomPath); - mapForGetData.put("drive", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("imgCdrom")) { - if (Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgCdrom")).toString().isEmpty()) { - cdromfile = VMManager.quickScanISOFileInFolder(getRomPath); - } else { - cdromfile = Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgCdrom")).toString(); - } - mapForGetData.put("cdrom", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgCdrom")).toString().replaceAll(getRomPath, "")); - } else { - cdromfile = VMManager.quickScanISOFileInFolder(getRomPath); - mapForGetData.put("cdrom", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("bootFrom")) { - mapForGetData.put("bootFrom", listmapForGetData.get(pendingPosition).get("bootFrom")); - } else { - mapForGetData.put("bootFrom", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("isShowBootMenu")) { - mapForGetData.put("isShowBootMenu", listmapForGetData.get(pendingPosition).get("isShowBootMenu")); - } else { - mapForGetData.put("isShowBootMenu", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("imgExtra")) { - mapForGetData.put("qemu", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgExtra")).toString().replaceAll(getRomPath, "OhnoIjustrealizeditsmidnightandIstillhavetodothis")); - } else { - mapForGetData.put("qemu", ""); - } - if (listmapForGetData.get(pendingPosition).containsKey("imgArch")) { - mapForGetData.put("arch", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgArch")).toString()); - } else { - mapForGetData.put("arch", ""); + vmConfigMap.put("cdrom", VMManager.quickScanISOFileInFolder(getRomPath)); } + + vmConfigMap.put("bootFrom", current.bootFrom); + vmConfigMap.put("isShowBootMenu", current.isShowBootMenu); + vmConfigMap.put("qemu", current.itemExtra); + vmConfigMap.put("arch", current.itemArch); + if (Objects.requireNonNull(binding.edAuthor.getText()).toString().isEmpty()) { - mapForGetData.put("author", "Unknow"); + vmConfigMap.put("author", "Unknow"); } else { - mapForGetData.put("author", binding.edAuthor.getText().toString()); + vmConfigMap.put("author", binding.edAuthor.getText().toString()); } if (Objects.requireNonNull(binding.edContent.getText()).toString().isEmpty()) { - mapForGetData.put("desc", "Empty."); + vmConfigMap.put("desc", "Empty."); } else { - mapForGetData.put("desc", binding.edContent.getText().toString()); + vmConfigMap.put("desc", binding.edContent.getText().toString()); } - mapForGetData.put("versioncode", PackageUtils.getThisVersionCode(getApplicationContext())); + vmConfigMap.put("versioncode", PackageUtils.getThisVersionCode(getApplicationContext())); - FileUtils.writeToFile(new File(String.valueOf(getExternalFilesDir("data"))).getPath(), "rom-data.json", new Gson().toJson(mapForGetData)); + FileUtils.writeToFile(new File(String.valueOf(getExternalFilesDir("data"))).getPath(), "rom-data.json", new Gson().toJson(vmConfigMap)); String[] filePaths = new String[0]; ArrayList _filelist = new ArrayList<>(); - FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder + Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("vmID")), _filelist); + FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder + current.vmID, _filelist); if (!_filelist.isEmpty()) { for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) { if (!_filelist.get(_repeat).endsWith("vmID.txt") && @@ -215,14 +188,15 @@ public class ExportRomActivity extends AppCompatActivity { isExporting = true; String outputPath; - if (!FileUtils.isFileExists(AppConfig.cvbiFolder + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi")) { - outputPath = AppConfig.cvbiFolder + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"; + String outputFileName = current.itemName + ".cvbi"; + if (!FileUtils.isFileExists(cvbiFolder + current.itemName + ".cvbi")) { + outputPath = cvbiFolder + outputFileName; } else { - String outputFileName = Objects.requireNonNull(mapForGetData.get("title")).toString(); int prefix = 0; while (true) { - if (!FileUtils.isFileExists(AppConfig.cvbiFolder + outputFileName + "_" + prefix + ".cvbi")) { - outputPath = AppConfig.cvbiFolder + outputFileName + "_" + prefix + ".cvbi"; + if (!FileUtils.isFileExists(cvbiFolder + current.itemName + "_" + prefix + ".cvbi")) { + outputFileName = current.itemName + "_" + prefix + ".cvbi"; + outputPath = cvbiFolder + outputFileName; break; } else { prefix++; @@ -230,23 +204,31 @@ public class ExportRomActivity extends AppCompatActivity { } } - boolean result = ZipUtils.compress( + final boolean[] result = {ZipUtils.compress( this, finalFilePaths, - outputPath, + uri, progressText, progressBar - ); - + )}; runOnUiThread(() -> { isExporting = false; progressDialog.dismiss(); + String finalOutputPath = ""; + try { + FileUtils.deleteDirectory(outputPath); + finalOutputPath = FileUtils.getPath(this, uri); + } catch (Exception e) { + Log.e(TAG, "startCreate: ", e); + } + + String finalOutputPath1 = finalOutputPath; String title; String content; - if (result) { + if (result[0]) { title = getString(R.string.done); - content = getString(R.string.saved_in) + ": " + outputPath + "."; + content = finalOutputPath1 == null || finalOutputPath1.isEmpty() ? getString(R.string.rom_successfully_exported) : getString(R.string.saved_in) + ": " + finalOutputPath1 + "."; } else { title = getString(R.string.oops); content = getString(R.string.something_went_wrong) + ":\n\n" + ZipUtils.lastErrorContent; @@ -255,19 +237,20 @@ public class ExportRomActivity extends AppCompatActivity { DialogUtils.twoDialog(this, title, content, - getString(result ? R.string.show_in_folder : R.string.ok), - getString(result ? R.string.close : R.string.exit), + getString(result[0] ? R.string.show_in_folder : R.string.ok), + getString(result[0] ? R.string.close : R.string.exit), true, - result ? R.drawable.check_24px : R.drawable.error_96px, + result[0] ? R.drawable.check_24px : R.drawable.error_96px, true, () -> { - if (result) { - File file = new File(outputPath); + if (result[0]) { + assert finalOutputPath1 != null; + File file = new File(finalOutputPath1.isEmpty() ? outputPath : finalOutputPath1); FileUtils.openFolder(this, file.getParent()); } }, () -> { - if (!result) { + if (!result[0]) { finish(); } }, diff --git a/app/src/main/java/com/vectras/vm/Minitools.java b/app/src/main/java/com/vectras/vm/Minitools.java index 7ae8532..3501f78 100644 --- a/app/src/main/java/com/vectras/vm/Minitools.java +++ b/app/src/main/java/com/vectras/vm/Minitools.java @@ -310,30 +310,4 @@ public class Minitools extends AppCompatActivity { }); }).start(); } - - public void extractLoaderApk() { - String apkLoaderAssetPath = "bootstrap/loader.apk"; - String apkLoaderextractedFilePath = TermuxService.PREFIX_PATH + "/libexec/termux-x11/loader.apk"; - - FileUtils.deleteDirectory(apkLoaderextractedFilePath); - if (copyAssetToFile(apkLoaderAssetPath, apkLoaderextractedFilePath)) { - FileUtils.copyAFile(TermuxService.PREFIX_PATH + "/libexec/termux-x11/loader.apk", AppConfig.maindirpath); - } - } - - private boolean copyAssetToFile(String assetPath, String outputPath) { - try (InputStream in = getAssets().open(assetPath); - OutputStream out = new FileOutputStream(outputPath)) { - byte[] buffer = new byte[1024]; - int read; - while ((read = in.read(buffer)) != -1) { - out.write(buffer, 0, read); - } - out.flush(); - return true; - } catch (IOException e) { - Log.e(TAG, "copyAssetToFile: ", e); - return false; - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/VMManager.java b/app/src/main/java/com/vectras/vm/VMManager.java index 40739a9..9a00d52 100644 --- a/app/src/main/java/com/vectras/vm/VMManager.java +++ b/app/src/main/java/com/vectras/vm/VMManager.java @@ -983,10 +983,7 @@ public class VMManager { public static void killallqemuprocesses(Context context) { Terminal vterm = new Terminal(context); - vterm.executeShellCommand2("killall -15 qemu-system-i386", false, null); - vterm.executeShellCommand2("killall -15 qemu-system-x86_64", false, null); - vterm.executeShellCommand2("killall -15 qemu-system-aarch64", false, null); - vterm.executeShellCommand2("killall -15 qemu-system-ppc", false, null); + vterm.executeShellCommand2("killall -15 qemu-system-i386 && killall -15 qemu-system-x86_64 && killall -15 qemu-system-aarch64 && killall -15 qemu-system-ppc", false, null); } public static void shutdownCurrentVM() { diff --git a/app/src/main/java/com/vectras/vm/QemuParamsEditorActivity.java b/app/src/main/java/com/vectras/vm/creator/QemuParamsEditorActivity.java similarity index 96% rename from app/src/main/java/com/vectras/vm/QemuParamsEditorActivity.java rename to app/src/main/java/com/vectras/vm/creator/QemuParamsEditorActivity.java index d60d75e..3daa9dd 100644 --- a/app/src/main/java/com/vectras/vm/QemuParamsEditorActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/QemuParamsEditorActivity.java @@ -1,4 +1,4 @@ -package com.vectras.vm; +package com.vectras.vm.creator; import android.os.Bundle; import android.os.Handler; @@ -7,6 +7,7 @@ import android.view.inputmethod.InputMethodManager; import androidx.appcompat.app.AppCompatActivity; +import com.vectras.vm.R; import com.vectras.vm.databinding.ActivityQemuParamsEditorBinding; import com.vectras.vm.utils.UIUtils; diff --git a/app/src/main/java/com/vectras/vm/SetArchActivity.java b/app/src/main/java/com/vectras/vm/creator/SetArchActivity.java similarity index 96% rename from app/src/main/java/com/vectras/vm/SetArchActivity.java rename to app/src/main/java/com/vectras/vm/creator/SetArchActivity.java index 5665791..3f42d75 100644 --- a/app/src/main/java/com/vectras/vm/SetArchActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/SetArchActivity.java @@ -1,153 +1,153 @@ -package com.vectras.vm; - -import android.content.ClipData; -import android.content.ClipDescription; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.view.DragEvent; -import android.view.Menu; -import android.view.View; - -import androidx.appcompat.app.AppCompatActivity; - -import com.vectras.qemu.MainSettingsManager; -import com.vectras.vm.creator.VMCreatorActivity; -import com.vectras.vm.databinding.ActivitySetArchBinding; -import com.vectras.vm.main.MainActivity; -import com.vectras.vm.utils.FileUtils; -import com.vectras.vm.utils.UIUtils; - -import java.io.File; - -public class SetArchActivity extends AppCompatActivity implements View.OnClickListener { - - SetArchActivity activity; - ActivitySetArchBinding binding; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - UIUtils.edgeToEdge(this); - binding = ActivitySetArchBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); -// UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main)); - activity = this; - binding.archi386.setOnClickListener(this); - binding.archx8664.setOnClickListener(this); - binding.archarm64.setOnClickListener(this); - binding.archppc.setOnClickListener(this); - binding.webBtn.setOnClickListener(this); - binding.buttongetcm.setOnClickListener(this); - binding.bntimport.setOnClickListener(this); - - setSupportActionBar(binding.toolbar); - binding.toolbar.setNavigationOnClickListener(v -> finish()); - - binding.toolbar.setOnMenuItemClickListener(item -> { - if (item.getItemId() == R.id.roms_store) { - MainActivity.isOpenRomStore = true; - finish(); - return true; - } - return false; - }); - -// if (PackageUtils.isInstalled("com.anbui.cqcm.app", this)) { -// binding.buttongetcm.setText(getResources().getString(R.string.open)); -// } - - binding.bntimport.setOnDragListener((v, event) -> { - Log.i("Drag", "onDrag: " + event.getAction()); - switch (event.getAction()) { - case DragEvent.ACTION_DRAG_STARTED: - ClipDescription description = event.getClipDescription(); - if (description != null) { - Log.d("DRAG", "MIME: " + description.getMimeType(0)); - return true; // Accept to go to event DragEvent.ACTION_DROP - } - return false; - - case DragEvent.ACTION_DROP: - ClipData clipData = event.getClipData(); - if (clipData != null && clipData.getItemCount() > 0) { - Uri uri = clipData.getItemAt(0).getUri(); - String filePath = FileUtils.getFilePathFromUri(getApplicationContext(), uri); - - File file = new File(filePath); - - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), VMCreatorActivity.class); - intent.putExtra("addromnow", ""); - intent.putExtra("romextra", ""); - intent.putExtra("romname", ""); - intent.putExtra("romicon", ""); - intent.putExtra("rompath", filePath); - intent.putExtra("romfilename", file.getName()); - startActivity(intent); - finish(); - } - return true; - } - return true; - }); - - } - - public void onClick(View v) { - int id = v.getId(); - if (id == R.id.archi386) { - MainSettingsManager.setArch(this, "I386"); - - startActivity(new Intent(activity, VMCreatorActivity.class)); - finish(); - } else if (id == R.id.archx86_64) { - MainSettingsManager.setArch(this, "X86_64"); - - startActivity(new Intent(activity, VMCreatorActivity.class)); - finish(); - } else if (id == R.id.archarm64) { - MainSettingsManager.setArch(this, "ARM64"); - - startActivity(new Intent(activity, VMCreatorActivity.class)); - finish(); - } else if (id == R.id.archppc) { - MainSettingsManager.setArch(this, "PPC"); - - startActivity(new Intent(activity, VMCreatorActivity.class)); - finish(); - } else if (id == R.id.webBtn) { - String qe = "https://www.qemu.org/"; - Intent q = new Intent(Intent.ACTION_VIEW); - q.addCategory(Intent.CATEGORY_BROWSABLE); - q.setData(Uri.parse(qe)); - startActivity(q); - } else if (id == R.id.buttongetcm) { - PackageManager pm = getPackageManager(); - Intent intent = pm.getLaunchIntentForPackage("com.anbui.cqcm.app"); - - if (intent != null) { - startActivity(intent); - } else { - Intent intenturl = new Intent(); - intenturl.setAction(Intent.ACTION_VIEW); - intenturl.setData(Uri.parse("https://play.google.com/store/apps/details?id=com.anbui.cqcm.app")); - startActivity(intenturl); - } - } else if (id == R.id.bntimport) { - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), VMCreatorActivity.class); - intent.putExtra("importcvbinow", ""); - startActivity(intent); - finish(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.set_arch_toolbar_menu, menu); - return true; - } +package com.vectras.vm.creator; + +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.DragEvent; +import android.view.Menu; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.R; +import com.vectras.vm.databinding.ActivitySetArchBinding; +import com.vectras.vm.main.MainActivity; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.UIUtils; + +import java.io.File; + +public class SetArchActivity extends AppCompatActivity implements View.OnClickListener { + + SetArchActivity activity; + ActivitySetArchBinding binding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + UIUtils.edgeToEdge(this); + binding = ActivitySetArchBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); +// UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main)); + activity = this; + binding.archi386.setOnClickListener(this); + binding.archx8664.setOnClickListener(this); + binding.archarm64.setOnClickListener(this); + binding.archppc.setOnClickListener(this); + binding.webBtn.setOnClickListener(this); + binding.buttongetcm.setOnClickListener(this); + binding.bntimport.setOnClickListener(this); + + setSupportActionBar(binding.toolbar); + binding.toolbar.setNavigationOnClickListener(v -> finish()); + + binding.toolbar.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.roms_store) { + MainActivity.isOpenRomStore = true; + finish(); + return true; + } + return false; + }); + +// if (PackageUtils.isInstalled("com.anbui.cqcm.app", this)) { +// binding.buttongetcm.setText(getResources().getString(R.string.open)); +// } + + binding.bntimport.setOnDragListener((v, event) -> { + Log.i("Drag", "onDrag: " + event.getAction()); + switch (event.getAction()) { + case DragEvent.ACTION_DRAG_STARTED: + ClipDescription description = event.getClipDescription(); + if (description != null) { + Log.d("DRAG", "MIME: " + description.getMimeType(0)); + return true; // Accept to go to event DragEvent.ACTION_DROP + } + return false; + + case DragEvent.ACTION_DROP: + ClipData clipData = event.getClipData(); + if (clipData != null && clipData.getItemCount() > 0) { + Uri uri = clipData.getItemAt(0).getUri(); + String filePath = FileUtils.getFilePathFromUri(getApplicationContext(), uri); + + File file = new File(filePath); + + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), VMCreatorActivity.class); + intent.putExtra("addromnow", ""); + intent.putExtra("romextra", ""); + intent.putExtra("romname", ""); + intent.putExtra("romicon", ""); + intent.putExtra("rompath", filePath); + intent.putExtra("romfilename", file.getName()); + startActivity(intent); + finish(); + } + return true; + } + return true; + }); + + } + + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.archi386) { + MainSettingsManager.setArch(this, "I386"); + + startActivity(new Intent(activity, VMCreatorActivity.class)); + finish(); + } else if (id == R.id.archx86_64) { + MainSettingsManager.setArch(this, "X86_64"); + + startActivity(new Intent(activity, VMCreatorActivity.class)); + finish(); + } else if (id == R.id.archarm64) { + MainSettingsManager.setArch(this, "ARM64"); + + startActivity(new Intent(activity, VMCreatorActivity.class)); + finish(); + } else if (id == R.id.archppc) { + MainSettingsManager.setArch(this, "PPC"); + + startActivity(new Intent(activity, VMCreatorActivity.class)); + finish(); + } else if (id == R.id.webBtn) { + String qe = "https://www.qemu.org/"; + Intent q = new Intent(Intent.ACTION_VIEW); + q.addCategory(Intent.CATEGORY_BROWSABLE); + q.setData(Uri.parse(qe)); + startActivity(q); + } else if (id == R.id.buttongetcm) { + PackageManager pm = getPackageManager(); + Intent intent = pm.getLaunchIntentForPackage("com.anbui.cqcm.app"); + + if (intent != null) { + startActivity(intent); + } else { + Intent intenturl = new Intent(); + intenturl.setAction(Intent.ACTION_VIEW); + intenturl.setData(Uri.parse("https://play.google.com/store/apps/details?id=com.anbui.cqcm.app")); + startActivity(intenturl); + } + } else if (id == R.id.bntimport) { + Intent intent = new Intent(); + intent.setClass(getApplicationContext(), VMCreatorActivity.class); + intent.putExtra("importcvbinow", ""); + startActivity(intent); + finish(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.set_arch_toolbar_menu, menu); + return true; + } } \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java index cfccaaf..aa9e0fc 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java @@ -28,7 +28,6 @@ import com.google.gson.Gson; import com.vectras.qemu.MainSettingsManager; import com.vectras.vm.AppConfig; import com.vectras.vm.Fragment.CreateImageDialogFragment; -import com.vectras.vm.QemuParamsEditorActivity; import com.vectras.vm.R; import com.vectras.vm.RomInfo; import com.vectras.vm.SplashActivity; @@ -674,7 +673,7 @@ public class VMCreatorActivity extends AppCompatActivity { null)); } finally { runOnUiThread(() -> { - if (!isImportingCVBI && !isFinishing() && !isDestroyed()) + if (!isImportingCVBI && progressDialog.isShowing() && !isFinishing() && !isDestroyed()) progressDialog.dismiss(); }); } @@ -879,13 +878,14 @@ public class VMCreatorActivity extends AppCompatActivity { ); runOnUiThread(() -> { + if (progressDialog.isShowing() && !isFinishing() && !isDestroyed()) + progressDialog.dismiss(); + if (isFinishing() || isDestroyed()) { new Thread(() -> FileUtils.deleteDirectory(AppConfig.vmFolder + vmID)).start(); return; } - progressDialog.dismiss(); - if (result) { afterExtractCVBIFile(fileName); } else { diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java index 5136827..be388ea 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java @@ -2,8 +2,6 @@ package com.vectras.vm.creator; import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -14,14 +12,10 @@ import androidx.appcompat.app.AlertDialog; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import com.vectras.vm.R; -import com.vectras.vm.databinding.RecyclerViewBinding; +import com.vectras.vm.databinding.DialogListSelectorLayoutBinding; import com.vectras.vm.databinding.SimpleLayoutListViewWithCheckBinding; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; @@ -43,20 +37,31 @@ public class VMCreatorSelector { public static void showDialog(Activity activity, ArrayList> list, int position,SelectorCallback callback, String title) { LinearLayoutManager layoutmanager = new LinearLayoutManager(activity); - RecyclerViewBinding binding = RecyclerViewBinding.inflate(activity.getLayoutInflater()); + DialogListSelectorLayoutBinding binding = DialogListSelectorLayoutBinding.inflate(activity.getLayoutInflater()); AlertDialog dialog = new AlertDialog.Builder(activity) .setView(binding.getRoot()) .create(); - dialog.setTitle(title); - dialog.setButton(AlertDialog.BUTTON_POSITIVE, activity.getString(R.string.close), (dialog1, which) -> dialog1.dismiss()); + binding.tvTitle.setText(title); + binding.btnClose.setOnClickListener(v -> dialog.dismiss()); binding.list.setAdapter(new RecyclerviewAdapter(activity, dialog, list, position, callback)); binding.list.setLayoutManager(layoutmanager); dialog.show(); + binding.list.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView rv, int dx, int dy) { + boolean canScrollUp = rv.canScrollVertically(-1); + boolean canScrollDown = rv.canScrollVertically(1); + + binding.dvTop.setVisibility(canScrollUp ? View.VISIBLE : View.INVISIBLE); + binding.dvBottom.setVisibility(canScrollDown ? View.VISIBLE : View.INVISIBLE); + } + }); + if (position > -1) binding.list.scrollToPosition(position); } @@ -90,7 +95,7 @@ public class VMCreatorSelector { View view = holder.itemView; TextView title = view.findViewById(R.id.textview); title.setText(Objects.requireNonNull(data.get(position).get("name")).toString()); - view.findViewById(R.id.iv_check).setVisibility(position == currentPosition ? View.VISIBLE : View.GONE); + view.findViewById(R.id.iv_check).setVisibility(position == currentPosition ? View.VISIBLE : View.INVISIBLE); view.findViewById(R.id.main).setOnClickListener(v -> { callback.onSelected( position, diff --git a/app/src/main/java/com/vectras/vm/main/MainActivity.java b/app/src/main/java/com/vectras/vm/main/MainActivity.java index c63a7f1..13bfead 100644 --- a/app/src/main/java/com/vectras/vm/main/MainActivity.java +++ b/app/src/main/java/com/vectras/vm/main/MainActivity.java @@ -54,7 +54,7 @@ import com.vectras.vm.databinding.BottomsheetdialogLoggerBinding; import com.vectras.vm.databinding.UpdateBottomDialogLayoutBinding; import com.vectras.vm.main.romstore.RomStoreHomeAdapterSearch; import com.vectras.vm.main.romstore.DataRoms; -import com.vectras.vm.SetArchActivity; +import com.vectras.vm.creator.SetArchActivity; import com.vectras.vm.VMManager; import com.vectras.vm.adapter.LogsAdapter; import com.vectras.vm.main.core.CallbackInterface; @@ -69,6 +69,7 @@ import com.vectras.vm.settings.UpdaterActivity; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.IntentUtils; import com.vectras.vm.utils.LibraryChecker; import com.vectras.vm.utils.NotificationUtils; import com.vectras.vm.utils.PackageUtils; @@ -423,10 +424,7 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment. startActivity(new Intent(this, AboutActivity.class)); } if (id == R.id.navigation_item_help) { - String tw = AppConfig.vectrasHelp; - Intent w = new Intent(ACTION_VIEW); - w.setData(Uri.parse(tw)); - startActivity(w); + IntentUtils.openUrl(this, AppConfig.vectrasHelp, true); } else if (id == R.id.navigation_item_website) { String tw = AppConfig.vectrasWebsite; Intent w = new Intent(ACTION_VIEW); diff --git a/app/src/main/java/com/vectras/vm/main/core/RomOptionsDialog.java b/app/src/main/java/com/vectras/vm/main/core/RomOptionsDialog.java index 232dd91..0b91e6f 100644 --- a/app/src/main/java/com/vectras/vm/main/core/RomOptionsDialog.java +++ b/app/src/main/java/com/vectras/vm/main/core/RomOptionsDialog.java @@ -28,9 +28,9 @@ public class RomOptionsDialog { Button exportRomBtn = v.findViewById(R.id.exportRomBtn); exportRomBtn.setOnClickListener(v2 -> { - ExportRomActivity.pendingPosition = position; Intent intent = new Intent(); intent.setClass(activity, ExportRomActivity.class); + intent.putExtra("POS", position); activity.startActivity(intent); bottomSheetDialog.cancel(); }); diff --git a/app/src/main/java/com/vectras/vm/setupwizard/SetupWizard2Activity.java b/app/src/main/java/com/vectras/vm/setupwizard/SetupWizard2Activity.java index ecea5ed..a0f621f 100644 --- a/app/src/main/java/com/vectras/vm/setupwizard/SetupWizard2Activity.java +++ b/app/src/main/java/com/vectras/vm/setupwizard/SetupWizard2Activity.java @@ -44,6 +44,7 @@ import com.vectras.vm.main.MainActivity; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.IntentUtils; import com.vectras.vm.utils.JSONUtils; import com.vectras.vm.utils.ListUtils; import com.vectras.vm.utils.PermissionUtils; @@ -193,10 +194,7 @@ public class SetupWizard2Activity extends AppCompatActivity { uiController(STEP_SYSTEM_UPDATE); binding.btnSkipSystemUpdate.setVisibility(View.GONE); } else if (isLibProotError) { - Intent intent = new Intent(); - intent.setAction(ACTION_VIEW); - intent.setData(Uri.parse(AppConfig.telegramLink)); - startActivity(intent); + IntentUtils.openTelegramLink(this); } else if (SetupFeatureCore.isInstalledSystemFiles(this)) { getDataForStandardSetup(); } else { @@ -210,8 +208,7 @@ public class SetupWizard2Activity extends AppCompatActivity { bindingFinalSteps.btnContinue.setOnClickListener(v -> { if (currentStep == STEP_JOIN_COMMUNITY) { uiControllerFinalSteps(currentStep + 1); - Intent intent = new Intent(ACTION_VIEW, Uri.parse(AppConfig.telegramLink)); - startActivity(intent); + IntentUtils.openTelegramLink(this); //Don't show join Telegram dialog again SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor edit = prefs.edit(); @@ -772,7 +769,7 @@ public class SetupWizard2Activity extends AppCompatActivity { // Assign data HashMap item = data.get(position); holder.simpleLayoutListViewWithCheckBinding.textview.setText(item.get("location")); - holder.simpleLayoutListViewWithCheckBinding.ivCheck.setVisibility(position == selectedPosition ? View.VISIBLE : View.GONE); + holder.simpleLayoutListViewWithCheckBinding.ivCheck.setVisibility(position == selectedPosition ? View.VISIBLE : View.INVISIBLE); return convertView; diff --git a/app/src/main/java/com/vectras/vm/utils/DialogUtils.java b/app/src/main/java/com/vectras/vm/utils/DialogUtils.java index 5706cd1..9e5ccb4 100644 --- a/app/src/main/java/com/vectras/vm/utils/DialogUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/DialogUtils.java @@ -254,12 +254,7 @@ public class DialogUtils { _context.getResources().getString(R.string.join_us_on_telegram_where_we_publish_all_the_news_and_updates_and_receive_your_opinions_and_bugs), _context.getResources().getString(R.string.join), _context.getResources().getString(R.string.cancel), _context.getResources().getString(R.string.dont_show_again), true, R.drawable.send_24px, true, - () -> { - Intent intent = new Intent(ACTION_VIEW); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setData(Uri.parse(AppConfig.telegramLink)); - _context.startActivity(intent); - }, null, + () -> IntentUtils.openTelegramLink(_context), null, () -> { SharedPreferences.Editor edit = prefs.edit(); edit.putBoolean("tgDialog", true); diff --git a/app/src/main/java/com/vectras/vm/utils/FileUtils.java b/app/src/main/java/com/vectras/vm/utils/FileUtils.java index 34f0944..13f7b0a 100644 --- a/app/src/main/java/com/vectras/vm/utils/FileUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/FileUtils.java @@ -33,6 +33,7 @@ import android.os.ParcelFileDescriptor; import androidx.annotation.NonNull; import androidx.core.content.FileProvider; +import androidx.documentfile.provider.DocumentFile; import com.vectras.vm.R; @@ -47,563 +48,553 @@ import java.util.HashMap; import java.util.Objects; /** - * + * * @author dev */ public class FileUtils { - public static final String TAG = "FileUtils"; - - @NonNull - public static File getExternalFilesDirectory(Context context) { - return new File(Environment.getExternalStorageDirectory(), "Documents/VectrasVM"); - } - - public static void chmod(File file, int mode) { - try { - Os.chmod(file.getAbsolutePath(), mode); - } - catch (ErrnoException e) {} - } - - private static Uri contentUri = null; - - @SuppressLint("NewApi") - public static String getPath(Context context, final Uri uri) { - // check here to KITKAT or new version - final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - String selection = null; - String[] selectionArgs = null; - // DocumentProvider - if (isKitKat ) { - // ExternalStorageProvider - - if (isExternalStorageDocument(uri)) { - final String docId = DocumentsContract.getDocumentId(uri); - final String[] split = docId.split(":"); - final String type = split[0]; - - String fullPath = getPathFromExtSD(split); - if (fullPath != "") { - return fullPath; - } else { - return null; - } - } - - - // DownloadsProvider - - if (isDownloadsDocument(uri)) { - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - final String id; - Cursor cursor = null; - try { - cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - String fileName = cursor.getString(0); - String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName; - if (!TextUtils.isEmpty(path)) { - return path; - } - } - } - finally { - if (cursor != null) - cursor.close(); - } - id = DocumentsContract.getDocumentId(uri); - if (!TextUtils.isEmpty(id)) { - if (id.startsWith("raw:")) { - return id.replaceFirst("raw:", ""); - } - String[] contentUriPrefixesToTry = new String[]{ - "content://downloads/public_downloads", - "content://downloads/my_downloads" - }; - for (String contentUriPrefix : contentUriPrefixesToTry) { - try { - final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id)); - - - return getDataColumn(context, contentUri, null, null); - } catch (NumberFormatException e) { - //In Android 8 and Android P the id is not a number - return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", ""); - } - } - - - } - } - else { - final String id = DocumentsContract.getDocumentId(uri); - - if (id.startsWith("raw:")) { - return id.replaceFirst("raw:", ""); - } - try { - contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - } - catch (NumberFormatException e) { - e.printStackTrace(); - } - if (contentUri != null) { - - return getDataColumn(context, contentUri, null, null); - } - } - } - - - // MediaProvider - 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; - } - selection = "_id=?"; - selectionArgs = new String[]{split[1]}; - - - return getDataColumn(context, contentUri, selection, - selectionArgs); - } - - if (isGoogleDriveUri(uri)) { - return getDriveFilePath(context, uri); - } - - if(isWhatsAppFile(uri)){ - return getFilePathForWhatsApp(context, uri); - } - - - if ("content".equalsIgnoreCase(uri.getScheme())) { - - if (isGooglePhotosUri(uri)) { - return uri.getLastPathSegment(); - } - if (isGoogleDriveUri(uri)) { - return getDriveFilePath(context, uri); - } - if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) - { - - // return getFilePathFromURI(context,uri); - return copyFileToInternalStorage(context, uri,"userfiles"); - // return getRealPathFromURI(context,uri); - } - else - { - return getDataColumn(context, uri, null, null); - } - - } - if ("file".equalsIgnoreCase(uri.getScheme())) { - return uri.getPath(); - } - } - else { - - if(isWhatsAppFile(uri)){ - return getFilePathForWhatsApp(context, uri); - } - - if ("content".equalsIgnoreCase(uri.getScheme())) { - String[] projection = { - MediaStore.Images.Media.DATA - }; - Cursor cursor = null; - try { - cursor = context.getContentResolver() - .query(uri, projection, selection, selectionArgs, null); - int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - if (cursor.moveToFirst()) { - return cursor.getString(column_index); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - return null; - } - - private static boolean fileExists(String filePath) { - File file = new File(filePath); - - return file.exists(); - } - - private static String getPathFromExtSD(String[] pathData) { - final String type = pathData[0]; - final String relativePath = "/" + pathData[1]; - String fullPath = ""; - - // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string - // something like "71F8-2C0A", some kind of unique id per storage - // don't know any API that can get the root path of that storage based on its id. - // - // so no "primary" type, but let the check here for other devices - if ("primary".equalsIgnoreCase(type)) { - fullPath = Environment.getExternalStorageDirectory() + relativePath; - if (fileExists(fullPath)) { - return fullPath; - } - } - - // Environment.isExternalStorageRemovable() is `true` for external and internal storage - // so we cannot relay on it. - // - // instead, for each possible path, check if file exists - // we'll start with secondary storage as this could be our (physically) removable sd card - fullPath = System.getenv("SECONDARY_STORAGE") + relativePath; - if (fileExists(fullPath)) { - return fullPath; - } - - fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath; - if (fileExists(fullPath)) { - return fullPath; - } - - return fullPath; - } - - private static String getDriveFilePath(Context context, Uri uri) { - Uri returnUri = uri; - Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null); - /* - * Get the column indexes of the data in the Cursor, - * * move to the first row in the Cursor, get the data, - * * and display it. - * */ - int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); - returnCursor.moveToFirst(); - String name = (returnCursor.getString(nameIndex)); - String size = (Long.toString(returnCursor.getLong(sizeIndex))); - File file = new File(context.getCacheDir(), name); - try { - InputStream inputStream = context.getContentResolver().openInputStream(uri); - FileOutputStream outputStream = new FileOutputStream(file); - int read = 0; - int maxBufferSize = 1 * 1024 * 1024; - int bytesAvailable = inputStream.available(); - - //int bufferSize = 1024; - int bufferSize = Math.min(bytesAvailable, maxBufferSize); - - final byte[] buffers = new byte[bufferSize]; - while ((read = inputStream.read(buffers)) != -1) { - outputStream.write(buffers, 0, read); - } - Log.e("File Size", "Size " + file.length()); - inputStream.close(); - outputStream.close(); - Log.e("File Path", "Path " + file.getPath()); - Log.e("File Size", "Size " + file.length()); - } catch (Exception e) { - Log.e("Exception", e.getMessage()); - } - return file.getPath(); - } - - /*** - * Used for Android Q+ - * @param uri - * @param newDirName if you want to create a directory, you can set this variable - * @return - */ - private static String copyFileToInternalStorage(Context context, Uri uri, String newDirName) { - Uri returnUri = uri; - - Cursor returnCursor = context.getContentResolver().query(returnUri, new String[]{ - OpenableColumns.DISPLAY_NAME,OpenableColumns.SIZE - }, null, null, null); - - - /* - * Get the column indexes of the data in the Cursor, - * * move to the first row in the Cursor, get the data, - * * and display it. - * */ - int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); - returnCursor.moveToFirst(); - String name = (returnCursor.getString(nameIndex)); - String size = (Long.toString(returnCursor.getLong(sizeIndex))); - - File output; - if(!newDirName.equals("")) { - File dir = new File(context.getFilesDir() + "/" + newDirName); - if (!dir.exists()) { - dir.mkdir(); - } - output = new File(context.getFilesDir() + "/" + newDirName + "/" + name); - } - else{ - output = new File(context.getFilesDir() + "/" + name); - } - try { - InputStream inputStream = context.getContentResolver().openInputStream(uri); - FileOutputStream outputStream = new FileOutputStream(output); - int read = 0; - int bufferSize = 1024; - final byte[] buffers = new byte[bufferSize]; - while ((read = inputStream.read(buffers)) != -1) { - outputStream.write(buffers, 0, read); - } - - inputStream.close(); - outputStream.close(); - - } - catch (Exception e) { - - Log.e("Exception", e.getMessage()); - } - - return output.getPath(); - } - - private static String getFilePathForWhatsApp(Context context, Uri uri){ - return copyFileToInternalStorage(context, uri,"whatsapp"); - } - - private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { - if (uri == null) return null; - - 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; - } - - private static boolean isExternalStorageDocument(Uri uri) { - return "com.android.externalstorage.documents".equals(uri.getAuthority()); - } - - private static boolean isDownloadsDocument(Uri uri) { - return "com.android.providers.downloads.documents".equals(uri.getAuthority()); - } - - private static boolean isMediaDocument(Uri uri) { - return "com.android.providers.media.documents".equals(uri.getAuthority()); - } - - private static boolean isGooglePhotosUri(Uri uri) { - return "com.google.android.apps.photos.content".equals(uri.getAuthority()); - } - - public static boolean isWhatsAppFile(Uri uri){ - return "com.whatsapp.provider.media".equals(uri.getAuthority()); - } - - private static boolean isGoogleDriveUri(Uri uri) { - return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority()); - } - - - public String LoadFile(Activity activity, String fileName, boolean loadFromRawFolder) throws IOException { - // Create a InputStream to read the file into - InputStream iS; - if (loadFromRawFolder) { - // get the resource id from the file name - int rID = activity.getResources().getIdentifier(getClass().getPackage().getName() + ":raw/" + fileName, - null, null); - // get the file as a stream - iS = activity.getResources().openRawResource(rID); - } else { - // get the file as a stream - iS = activity.getResources().getAssets().open(fileName); - } - - ByteArrayOutputStream oS = new ByteArrayOutputStream(); - byte[] buffer = new byte[iS.available()]; - int bytesRead = 0; - while ((bytesRead = iS.read(buffer)) > 0) { - oS.write(buffer); - } - oS.close(); - iS.close(); - - // return the output stream as a String - return oS.toString(); - } - - public static void saveFileContents(String dBFile, String machinesToExport) { - // TODO Auto-generated method stub - byteArrayToFile(machinesToExport.getBytes(), new File(dBFile)); - } - - public static void byteArrayToFile(byte[] byteData, File filePath) { - - try { - FileOutputStream fos = new FileOutputStream(filePath); - fos.write(byteData); - fos.close(); - - } catch (FileNotFoundException ex) { - System.out.println("FileNotFoundException : " + ex); - } catch (IOException ioe) { - System.out.println("IOException : " + ioe); - } - - } - - public static String getDataDir(Context context) { - - String dataDir = context.getApplicationInfo().dataDir; - PackageManager m = context.getPackageManager(); - String packageName = context.getPackageName(); - Log.v("VMExecutor", "Found packageName: " + packageName); - - if (dataDir == null) { - dataDir = "/data/data/" + packageName; - } - return dataDir; - } - - public static boolean fileValid(Context context, String path) { - - if (path == null || path.equals("")) - return true; - if (path.startsWith("content://") || path.startsWith("/content/")) { - int fd = get_fd(context, path); - if (fd <= 0) - return false; - } else { - File file = new File(path); - return file.exists(); - } - return true; - } - - public static HashMap fds = new HashMap(); - - public static int get_fd(final Context context, String path) { - int fd = 0; - if (path == null) - return 0; - - if (path.startsWith("/content") || path.startsWith("content://")) { - path = path.replaceFirst("/content", "content:"); - - try { - ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(Uri.parse(path), "rw"); - fd = pfd.getFd(); - fds.put(fd, pfd); - } catch (final FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - Toast.makeText(context, "Error: " + e, Toast.LENGTH_SHORT).show(); - } - }); - } - } else { - try { - File file = new File(path); - if (!file.exists()) - file.createNewFile(); - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_WRITE_ONLY); - fd = pfd.getFd(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - return fd; - } - - public static int close_fd(int fd) { - - if (FileUtils.fds.containsKey(fd)) { - ParcelFileDescriptor pfd = FileUtils.fds.get(fd); - try { - pfd.close(); - FileUtils.fds.remove(fd); - return 0; // success for Native side - } catch (IOException e) { - e.printStackTrace(); - } - - } - return -1; - } - - public static void writeToFile(String data, File file, Context context) { - try { - FileOutputStream fileOutStream = new FileOutputStream(file); - OutputStreamWriter outputWriter = new OutputStreamWriter(fileOutStream); - outputWriter.write(data); - outputWriter.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static String readFromFile(Context context, File file) { - String contents = null; - try { - int length = (int) file.length(); - - byte[] bytes = new byte[length]; - - FileInputStream in = new FileInputStream(file); - try { - in.read(bytes); - } finally { - in.close(); - } - - contents = new String(bytes); - } catch (Exception e) { - UIUtils.toastLong(context, e.toString()); - return "error"; - } - return contents; - } - - public static boolean moveFile(String oldfilename, String newFolderPath, String newFilename) { - File folder = new File(newFolderPath); - if (!folder.exists()) - folder.mkdirs(); - - File oldfile = new File(oldfilename); - File newFile = new File(newFolderPath, newFilename); - - if (!newFile.exists()) { + public static final String TAG = "FileUtils"; + + @NonNull + public static File getExternalFilesDirectory(Context context) { + return new File(Environment.getExternalStorageDirectory(), "Documents/VectrasVM"); + } + + public static void chmod(File file, int mode) { + try { + Os.chmod(file.getAbsolutePath(), mode); + } catch (ErrnoException e) { + } + } + + private static Uri contentUri = null; + + @SuppressLint("NewApi") + public static String getPath(Context context, final Uri uri) { + // check here to KITKAT or new version + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + String selection = null; + String[] selectionArgs = null; + // DocumentProvider + if (isKitKat) { + // ExternalStorageProvider + + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + String fullPath = getPathFromExtSD(split); + if (fullPath != "") { + return fullPath; + } else { + return null; + } + } + + + // DownloadsProvider + + if (isDownloadsDocument(uri)) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + final String id; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + String fileName = cursor.getString(0); + String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName; + if (!TextUtils.isEmpty(path)) { + return path; + } + } + } finally { + if (cursor != null) + cursor.close(); + } + id = DocumentsContract.getDocumentId(uri); + if (!TextUtils.isEmpty(id)) { + if (id.startsWith("raw:")) { + return id.replaceFirst("raw:", ""); + } + String[] contentUriPrefixesToTry = new String[]{ + "content://downloads/public_downloads", + "content://downloads/my_downloads" + }; + for (String contentUriPrefix : contentUriPrefixesToTry) { + try { + final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id)); + + + return getDataColumn(context, contentUri, null, null); + } catch (NumberFormatException e) { + //In Android 8 and Android P the id is not a number + return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", ""); + } + } + + + } + } else { + final String id = DocumentsContract.getDocumentId(uri); + + if (id.startsWith("raw:")) { + return id.replaceFirst("raw:", ""); + } + try { + contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + if (contentUri != null) { + + return getDataColumn(context, contentUri, null, null); + } + } + } + + + // MediaProvider + 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; + } + selection = "_id=?"; + selectionArgs = new String[]{split[1]}; + + + return getDataColumn(context, contentUri, selection, + selectionArgs); + } + + if (isGoogleDriveUri(uri)) { + return getDriveFilePath(context, uri); + } + + if (isWhatsAppFile(uri)) { + return getFilePathForWhatsApp(context, uri); + } + + + if ("content".equalsIgnoreCase(uri.getScheme())) { + + if (isGooglePhotosUri(uri)) { + return uri.getLastPathSegment(); + } + if (isGoogleDriveUri(uri)) { + return getDriveFilePath(context, uri); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + + // return getFilePathFromURI(context,uri); + return copyFileToInternalStorage(context, uri, "userfiles"); + // return getRealPathFromURI(context,uri); + } else { + return getDataColumn(context, uri, null, null); + } + + } + if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + } else { + + if (isWhatsAppFile(uri)) { + return getFilePathForWhatsApp(context, uri); + } + + if ("content".equalsIgnoreCase(uri.getScheme())) { + String[] projection = { + MediaStore.Images.Media.DATA + }; + Cursor cursor = null; + try { + cursor = context.getContentResolver() + .query(uri, projection, selection, selectionArgs, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + if (cursor.moveToFirst()) { + return cursor.getString(column_index); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return null; + } + + private static boolean fileExists(String filePath) { + File file = new File(filePath); + + return file.exists(); + } + + private static String getPathFromExtSD(String[] pathData) { + final String type = pathData[0]; + final String relativePath = "/" + pathData[1]; + String fullPath = ""; + + // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string + // something like "71F8-2C0A", some kind of unique id per storage + // don't know any API that can get the root path of that storage based on its id. + // + // so no "primary" type, but let the check here for other devices + if ("primary".equalsIgnoreCase(type)) { + fullPath = Environment.getExternalStorageDirectory() + relativePath; + if (fileExists(fullPath)) { + return fullPath; + } + } + + // Environment.isExternalStorageRemovable() is `true` for external and internal storage + // so we cannot relay on it. + // + // instead, for each possible path, check if file exists + // we'll start with secondary storage as this could be our (physically) removable sd card + fullPath = System.getenv("SECONDARY_STORAGE") + relativePath; + if (fileExists(fullPath)) { + return fullPath; + } + + fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath; + if (fileExists(fullPath)) { + return fullPath; + } + + return fullPath; + } + + private static String getDriveFilePath(Context context, Uri uri) { + Uri returnUri = uri; + Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null); + /* + * Get the column indexes of the data in the Cursor, + * * move to the first row in the Cursor, get the data, + * * and display it. + * */ + int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); + returnCursor.moveToFirst(); + String name = (returnCursor.getString(nameIndex)); + String size = (Long.toString(returnCursor.getLong(sizeIndex))); + File file = new File(context.getCacheDir(), name); + try { + InputStream inputStream = context.getContentResolver().openInputStream(uri); + FileOutputStream outputStream = new FileOutputStream(file); + int read = 0; + int maxBufferSize = 1 * 1024 * 1024; + int bytesAvailable = inputStream.available(); + + //int bufferSize = 1024; + int bufferSize = Math.min(bytesAvailable, maxBufferSize); + + final byte[] buffers = new byte[bufferSize]; + while ((read = inputStream.read(buffers)) != -1) { + outputStream.write(buffers, 0, read); + } + Log.e("File Size", "Size " + file.length()); + inputStream.close(); + outputStream.close(); + Log.e("File Path", "Path " + file.getPath()); + Log.e("File Size", "Size " + file.length()); + } catch (Exception e) { + Log.e("Exception", e.getMessage()); + } + return file.getPath(); + } + + /*** + * Used for Android Q+ + * @param uri + * @param newDirName if you want to create a directory, you can set this variable + * @return + */ + private static String copyFileToInternalStorage(Context context, Uri uri, String newDirName) { + Uri returnUri = uri; + + Cursor returnCursor = context.getContentResolver().query(returnUri, new String[]{ + OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE + }, null, null, null); + + + /* + * Get the column indexes of the data in the Cursor, + * * move to the first row in the Cursor, get the data, + * * and display it. + * */ + int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); + returnCursor.moveToFirst(); + String name = (returnCursor.getString(nameIndex)); + String size = (Long.toString(returnCursor.getLong(sizeIndex))); + + File output; + if (!newDirName.equals("")) { + File dir = new File(context.getFilesDir() + "/" + newDirName); + if (!dir.exists()) { + dir.mkdir(); + } + output = new File(context.getFilesDir() + "/" + newDirName + "/" + name); + } else { + output = new File(context.getFilesDir() + "/" + name); + } + try { + InputStream inputStream = context.getContentResolver().openInputStream(uri); + FileOutputStream outputStream = new FileOutputStream(output); + int read = 0; + int bufferSize = 1024; + final byte[] buffers = new byte[bufferSize]; + while ((read = inputStream.read(buffers)) != -1) { + outputStream.write(buffers, 0, read); + } + + inputStream.close(); + outputStream.close(); + + } catch (Exception e) { + + Log.e("Exception", e.getMessage()); + } + + return output.getPath(); + } + + private static String getFilePathForWhatsApp(Context context, Uri uri) { + return copyFileToInternalStorage(context, uri, "whatsapp"); + } + + private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + if (uri == null) return null; + + 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; + } + + private static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + private static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + private static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + private static boolean isGooglePhotosUri(Uri uri) { + return "com.google.android.apps.photos.content".equals(uri.getAuthority()); + } + + public static boolean isWhatsAppFile(Uri uri) { + return "com.whatsapp.provider.media".equals(uri.getAuthority()); + } + + private static boolean isGoogleDriveUri(Uri uri) { + return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority()); + } + + + public String LoadFile(Activity activity, String fileName, boolean loadFromRawFolder) throws IOException { + // Create a InputStream to read the file into + InputStream iS; + if (loadFromRawFolder) { + // get the resource id from the file name + int rID = activity.getResources().getIdentifier(getClass().getPackage().getName() + ":raw/" + fileName, + null, null); + // get the file as a stream + iS = activity.getResources().openRawResource(rID); + } else { + // get the file as a stream + iS = activity.getResources().getAssets().open(fileName); + } + + ByteArrayOutputStream oS = new ByteArrayOutputStream(); + byte[] buffer = new byte[iS.available()]; + int bytesRead = 0; + while ((bytesRead = iS.read(buffer)) > 0) { + oS.write(buffer); + } + oS.close(); + iS.close(); + + // return the output stream as a String + return oS.toString(); + } + + public static void saveFileContents(String dBFile, String machinesToExport) { + // TODO Auto-generated method stub + byteArrayToFile(machinesToExport.getBytes(), new File(dBFile)); + } + + public static void byteArrayToFile(byte[] byteData, File filePath) { + + try { + FileOutputStream fos = new FileOutputStream(filePath); + fos.write(byteData); + fos.close(); + + } catch (FileNotFoundException ex) { + System.out.println("FileNotFoundException : " + ex); + } catch (IOException ioe) { + System.out.println("IOException : " + ioe); + } + + } + + public static String getDataDir(Context context) { + + String dataDir = context.getApplicationInfo().dataDir; + PackageManager m = context.getPackageManager(); + String packageName = context.getPackageName(); + Log.v("VMExecutor", "Found packageName: " + packageName); + + if (dataDir == null) { + dataDir = "/data/data/" + packageName; + } + return dataDir; + } + + public static boolean fileValid(Context context, String path) { + + if (path == null || path.equals("")) + return true; + if (path.startsWith("content://") || path.startsWith("/content/")) { + int fd = get_fd(context, path); + if (fd <= 0) + return false; + } else { + File file = new File(path); + return file.exists(); + } + return true; + } + + public static HashMap fds = new HashMap(); + + public static int get_fd(final Context context, String path) { + int fd = 0; + if (path == null) + return 0; + + if (path.startsWith("/content") || path.startsWith("content://")) { + path = path.replaceFirst("/content", "content:"); + + try { + ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(Uri.parse(path), "rw"); + fd = pfd.getFd(); + fds.put(fd, pfd); + } catch (final FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + Toast.makeText(context, "Error: " + e, Toast.LENGTH_SHORT).show(); + } + }); + } + } else { + try { + File file = new File(path); + if (!file.exists()) + file.createNewFile(); + ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_WRITE_ONLY); + fd = pfd.getFd(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return fd; + } + + public static int close_fd(int fd) { + + if (FileUtils.fds.containsKey(fd)) { + ParcelFileDescriptor pfd = FileUtils.fds.get(fd); + try { + pfd.close(); + FileUtils.fds.remove(fd); + return 0; // success for Native side + } catch (IOException e) { + e.printStackTrace(); + } + + } + return -1; + } + + public static void writeToFile(String data, File file, Context context) { + try { + FileOutputStream fileOutStream = new FileOutputStream(file); + OutputStreamWriter outputWriter = new OutputStreamWriter(fileOutStream); + outputWriter.write(data); + outputWriter.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String readFromFile(Context context, File file) { + String contents = null; + try { + int length = (int) file.length(); + + byte[] bytes = new byte[length]; + + FileInputStream in = new FileInputStream(file); + try { + in.read(bytes); + } finally { + in.close(); + } + + contents = new String(bytes); + } catch (Exception e) { + UIUtils.toastLong(context, e.toString()); + return "error"; + } + return contents; + } + + public static boolean moveFile(String oldfilename, String newFolderPath, String newFilename) { + File folder = new File(newFolderPath); + if (!folder.exists()) + folder.mkdirs(); + + File oldfile = new File(oldfilename); + File newFile = new File(newFolderPath, newFilename); + + if (!newFile.exists()) { try { newFile.createNewFile(); } catch (IOException e) { @@ -611,74 +602,74 @@ public class FileUtils { e.printStackTrace(); } } - return oldfile.renameTo(newFile); - } + return oldfile.renameTo(newFile); + } - public static boolean isFileExists(String filePath) { - File file = new File(filePath.replaceAll("\n", "")); - return file.exists(); - } + public static boolean isFileExists(String filePath) { + File file = new File(filePath.replaceAll("\n", "")); + return file.exists(); + } - public static void moveAFile(String _from, String _to) { - File oldFile = new File(_from); - File newFile = new File(_to); + public static void moveAFile(String _from, String _to) { + File oldFile = new File(_from); + File newFile = new File(_to); - boolean success = oldFile.renameTo(newFile); - if (success) { - Log.d("File", "Done!"); - } else { - Log.e("File", "Failed!"); - } - } + boolean success = oldFile.renameTo(newFile); + if (success) { + Log.d("File", "Done!"); + } else { + Log.e("File", "Failed!"); + } + } - public static void copyAFile(String _sourceFile, String _destFile) { - File vDir = new File(_destFile.substring((int)0, (int)(_destFile.lastIndexOf("/")))); - if (!vDir.exists()) { - vDir.mkdirs(); - } - try { - File source = new File(_sourceFile); - File dest = new File(_destFile); + public static boolean copyFile(String _sourceFile, String _destFile) { + File vDir = new File(_destFile.substring(0, _destFile.lastIndexOf("/"))); + if (!vDir.exists() && vDir.mkdirs()) { + return false; + } + try { + File source = new File(_sourceFile); + File dest = new File(_destFile); - if (!source.exists()) - { - throw new IOException("Source file not found"); - } + if (!source.exists()) { + return false; + } - FileInputStream inStream = new FileInputStream(source); - FileOutputStream outStream = new FileOutputStream(dest); + FileInputStream inStream = new FileInputStream(source); + FileOutputStream outStream = new FileOutputStream(dest); - byte[] buffer = new byte[1024]; - int length; - while ((length = inStream.read(buffer)) - > 0) { - outStream.write(buffer, 0, length); - } + byte[] buffer = new byte[1024]; + int length; + while ((length = inStream.read(buffer)) + > 0) { + outStream.write(buffer, 0, length); + } - inStream.close(); - outStream.close(); - } catch (IOException e) { + inStream.close(); + outStream.close(); + } catch (IOException e) { + return false; + } + return true; + } - } + public static void copyFileFromUri(Context context, Uri sourceUri, String destFile) throws IOException { - } - - public static void copyFileFromUri(Context context, Uri sourceUri, String destFile) throws IOException { - - File file = new File(destFile); - if (!Objects.requireNonNull(file.getParentFile()).exists()) { - file.getParentFile().mkdirs(); - } + File file = new File(destFile); + if (!Objects.requireNonNull(file.getParentFile()).exists()) { + if (!file.getParentFile().mkdirs()) + throw new IOException("Failed to create directory: " + file.getParentFile().getAbsolutePath()); + } try (InputStream inputStream = context.getContentResolver().openInputStream(sourceUri); OutputStream outputStream = new FileOutputStream(destFile)) { - byte[] buffer = new byte[32 * 1024]; - if (DeviceUtils.totalMemoryCapacity(context) < 3L * 1024 * 1024 * 1024) { - buffer = new byte[4 * 1024]; - } else if (DeviceUtils.totalMemoryCapacity(context) < 5L * 1024 * 1024 * 1024) { - buffer = new byte[8 * 1024]; - } else if (DeviceUtils.totalMemoryCapacity(context) < 7L * 1024 * 1024 * 1024) { - buffer = new byte[16 * 1024]; - } + byte[] buffer = new byte[32 * 1024]; + if (DeviceUtils.totalMemoryCapacity(context) < 3L * 1024 * 1024 * 1024) { + buffer = new byte[4 * 1024]; + } else if (DeviceUtils.totalMemoryCapacity(context) < 5L * 1024 * 1024 * 1024) { + buffer = new byte[8 * 1024]; + } else if (DeviceUtils.totalMemoryCapacity(context) < 7L * 1024 * 1024 * 1024) { + buffer = new byte[16 * 1024]; + } int bytesRead; while (true) { assert inputStream != null; @@ -688,240 +679,265 @@ public class FileUtils { outputStream.flush(); } - } + } - public static String getFileNameFromUri(Context context, Uri uri) { - String result = null; + public static void copyFileToUri( + Context context, + String sourcePath, + Uri uri + ) throws Exception { - Cursor cursor = context.getContentResolver().query( - uri, - null, - null, - null, - null - ); + InputStream in = new FileInputStream(sourcePath); + OutputStream out = context.getContentResolver().openOutputStream(uri); + byte[] buffer = new byte[32 * 1024]; + if (DeviceUtils.totalMemoryCapacity(context) < 3L * 1024 * 1024 * 1024) { + buffer = new byte[4 * 1024]; + } else if (DeviceUtils.totalMemoryCapacity(context) < 5L * 1024 * 1024 * 1024) { + buffer = new byte[8 * 1024]; + } else if (DeviceUtils.totalMemoryCapacity(context) < 7L * 1024 * 1024 * 1024) { + buffer = new byte[16 * 1024]; + } + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + } - try { - if (cursor != null && cursor.moveToFirst()) { - int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - result = cursor.getString(nameIndex); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - if (result == null) { - result = uri.getLastPathSegment(); - } + public static String getFileNameFromUri(Context context, Uri uri) { + String result = null; - return result; - } + Cursor cursor = context.getContentResolver().query( + uri, + null, + null, + null, + null + ); - public static void deleteDirectory(String _pathToDelete) { - File _dir = new File(_pathToDelete); - if (_dir.isDirectory()) { - String[] children = _dir.list(); + try { + if (cursor != null && cursor.moveToFirst()) { + int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + result = cursor.getString(nameIndex); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } - if (children == null) { - Log.e("ERROR", "Deletion failed. " + _dir); - return; - } + if (result == null) { + result = uri.getLastPathSegment(); + } - for (int i = 0; i < children.length; i++) { - File temp = new File(_dir, children[i]); - deleteDirectory(String.valueOf(temp)); - } - } - boolean success = _dir.delete(); - if (!success) { - Log.e("ERROR", "Deletion failed. " + _dir); - } - } + return result; + } + + public static void deleteDirectory(String _pathToDelete) { + File _dir = new File(_pathToDelete); + if (_dir.isDirectory()) { + String[] children = _dir.list(); + + if (children == null) { + Log.e("ERROR", "Deletion failed. " + _dir); + return; + } + + for (int i = 0; i < children.length; i++) { + File temp = new File(_dir, children[i]); + deleteDirectory(String.valueOf(temp)); + } + } + boolean success = _dir.delete(); + if (!success) { + Log.e("ERROR", "Deletion failed. " + _dir); + } + } public static boolean canRead(String filePath) { File file = new File(filePath); return file.canRead(); } - public static String readAFile(String filePath) { - StringBuilder content = new StringBuilder(); - try (FileInputStream inputStream = new FileInputStream(filePath); - BufferedReader reader = new BufferedReader(new - InputStreamReader(inputStream))) { - String line; - while ((line = reader.readLine()) != null) { - content.append(line).append("\n"); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - return content.toString(); + public static String readAFile(String filePath) { + if (!FileUtils.isFileExists(filePath)) return ""; - } + StringBuilder content = new StringBuilder(); + try (FileInputStream inputStream = new FileInputStream(filePath); + BufferedReader reader = new BufferedReader(new + InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return content.toString(); - public static boolean writeToFile(String folderPath, String fileName, String content) { - File vDir = new File(folderPath); - if (!vDir.exists()) { - if (!vDir.mkdirs()) return false; - } - File file = new File(folderPath, fileName); - FileOutputStream outputStream; - try { - outputStream = new FileOutputStream(file); - outputStream.write(content.getBytes()); - outputStream.close(); - } catch (IOException e) { - Log.e(TAG, "writeToFile: ", e); - return false; - } - return true; - } + } - public static void getAListOfAllFilesAndFoldersInADirectory(String path, ArrayList list) { - File dir = new File(path); - if (!dir.exists() || dir.isFile()) return; + public static boolean writeToFile(String folderPath, String fileName, String content) { + File vDir = new File(folderPath); + if (!vDir.exists()) { + if (!vDir.mkdirs()) return false; + } + File file = new File(folderPath, fileName); + FileOutputStream outputStream; + try { + outputStream = new FileOutputStream(file); + outputStream.write(content.getBytes()); + outputStream.close(); + } catch (IOException e) { + Log.e(TAG, "writeToFile: ", e); + return false; + } + return true; + } - File[] listFiles = dir.listFiles(); - if (listFiles == null || listFiles.length <= 0) return; + public static void getAListOfAllFilesAndFoldersInADirectory(String path, ArrayList list) { + File dir = new File(path); + if (!dir.exists() || dir.isFile()) return; - if (list == null) return; - list.clear(); - for (File file : listFiles) { - list.add(file.getAbsolutePath()); - } - } + File[] listFiles = dir.listFiles(); + if (listFiles == null || listFiles.length <= 0) return; - public static int getFileSize(String _path) { - try { - File file = new File(_path); - if (!file.exists()) { - return 0; - } - return (int) file.length(); - } catch (Exception _e) { - return 0; - } - } + if (list == null) return; + list.clear(); + for (File file : listFiles) { + list.add(file.getAbsolutePath()); + } + } - public static long getFolderSize(String _path) { - try { - File file; - file = new File(_path); - if (file == null || !file.exists()) { - return 0; - } - if (!file.isDirectory()) { - return (int) file.length(); - } - final List dirs = new LinkedList<>(); - dirs.add(file); - long result = 0; - while (!dirs.isEmpty()) { - final File dir = dirs.remove(0); - if (!dir.exists()) { - continue; - } - final File[] listFiles = dir.listFiles(); - if (listFiles == null || listFiles.length == 0) { - continue; - } - for (final File child : listFiles) { - result += child.length(); - if (child.isDirectory()) { - dirs.add(child); - } - } - } - return result; - } catch (Exception _e) { - return 0; - } - } + public static int getFileSize(String _path) { + try { + File file = new File(_path); + if (!file.exists()) { + return 0; + } + return (int) file.length(); + } catch (Exception _e) { + return 0; + } + } - public static String getFilePathFromUri(Context context, Uri uri) { - String filePath = null; - if ("content".equalsIgnoreCase(uri.getScheme())) { - String[] projection = {MediaStore.Files.FileColumns.DATA}; + public static long getFolderSize(String _path) { + try { + File file; + file = new File(_path); + if (file == null || !file.exists()) { + return 0; + } + if (!file.isDirectory()) { + return (int) file.length(); + } + final List dirs = new LinkedList<>(); + dirs.add(file); + long result = 0; + while (!dirs.isEmpty()) { + final File dir = dirs.remove(0); + if (!dir.exists()) { + continue; + } + final File[] listFiles = dir.listFiles(); + if (listFiles == null || listFiles.length == 0) { + continue; + } + for (final File child : listFiles) { + result += child.length(); + if (child.isDirectory()) { + dirs.add(child); + } + } + } + return result; + } catch (Exception _e) { + return 0; + } + } + + public static String getFilePathFromUri(Context context, Uri uri) { + String filePath = null; + if ("content".equalsIgnoreCase(uri.getScheme())) { + String[] projection = {MediaStore.Files.FileColumns.DATA}; try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA); filePath = cursor.getString(index); } } catch (Exception e) { - Log.e(TAG, "getFilePathFromUri: ", e); + Log.e(TAG, "getFilePathFromUri: ", e); } - } else if ("file".equalsIgnoreCase(uri.getScheme())) { - filePath = uri.getPath(); - } - return filePath; - } + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + filePath = uri.getPath(); + } + return filePath; + } - public static boolean isValidFilePath(Activity activity, String filePath, boolean isShowDialog) { - if (filePath == null || filePath.isEmpty()) { - if (isShowDialog) { - DialogUtils.oneDialog(activity, - activity.getString(R.string.problem_has_been_detected), - activity.getString(R.string.invalid_file_path_content), - activity.getString(R.string.ok), - true, - R.drawable.folder_24px, - true, - null, - null); - } - return false; - } - return true; - } + public static boolean isValidFilePath(Activity activity, String filePath, boolean isShowDialog) { + if (filePath == null || filePath.isEmpty()) { + if (isShowDialog) { + DialogUtils.oneDialog(activity, + activity.getString(R.string.problem_has_been_detected), + activity.getString(R.string.invalid_file_path_content), + activity.getString(R.string.ok), + true, + R.drawable.folder_24px, + true, + null, + null); + } + return false; + } + return true; + } - public static void openFolder(Context context, String folderPath) { - File folder = new File(folderPath); + public static void openFolder(Context context, String folderPath) { + File folder = new File(folderPath); - if (!folder.exists() || !folder.isDirectory()) { - DialogUtils.oneDialog( - context, - context.getString(R.string.oops), - context.getString(R.string.directory_does_not_exist), - context.getString(R.string.ok), - true, - R.drawable.error_96px, - true, - null, - null - ); - Log.e(TAG, "openFolder: Folder not found!"); - return; - } + if (!folder.exists() || !folder.isDirectory()) { + DialogUtils.oneDialog( + context, + context.getString(R.string.oops), + context.getString(R.string.directory_does_not_exist), + context.getString(R.string.ok), + true, + R.drawable.error_96px, + true, + null, + null + ); + Log.e(TAG, "openFolder: Folder not found!"); + return; + } - Uri uri = FileProvider.getUriForFile( - context, - context.getPackageName() + ".provider", - folder - ); + Uri uri = FileProvider.getUriForFile( + context, + context.getPackageName() + ".provider", + folder + ); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(uri, "resource/folder"); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(uri, "resource/folder"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(intent); - } catch (Exception e) { - DialogUtils.oneDialog( - context, - context.getString(R.string.oops), - context.getString(R.string.there_is_no_app_to_perform_this_action), - context.getString(R.string.ok), - true, - R.drawable.error_96px, - true, - null, - null - ); - Log.e(TAG, "openFolder: " + e.getMessage()); - } - } + try { + context.startActivity(intent); + } catch (Exception e) { + DialogUtils.oneDialog( + context, + context.getString(R.string.oops), + context.getString(R.string.there_is_no_app_to_perform_this_action), + context.getString(R.string.ok), + true, + R.drawable.error_96px, + true, + null, + null + ); + Log.e(TAG, "openFolder: " + e.getMessage()); + } + } } diff --git a/app/src/main/java/com/vectras/vm/utils/IntentUtils.java b/app/src/main/java/com/vectras/vm/utils/IntentUtils.java new file mode 100644 index 0000000..19a0d50 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/utils/IntentUtils.java @@ -0,0 +1,44 @@ +package com.vectras.vm.utils; + +import static android.content.Intent.ACTION_VIEW; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; + +import com.vectras.vm.AppConfig; +import com.vectras.vm.R; + +public class IntentUtils { + public static boolean openTelegramLink(Context context) { + return openUrl(context, AppConfig.telegramLink, true); + } + + public static boolean openUrl(Context context, String url, boolean isShowErrorDialog) { + boolean result = openUrl(context, url); + if (isShowErrorDialog && !result) { + DialogUtils.oneDialog( + context, + context.getString(R.string.oops), + context.getString(R.string.there_is_no_app_to_perform_this_action), + R.drawable.error_96px + ); + } + return result; + } + + public static boolean openUrl(Context context, String url) { + Intent intent = new Intent(ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setData(Uri.parse(url)); + + PackageManager packagemanager = context.getPackageManager(); + if (intent.resolveActivity(packagemanager) != null) { + context.startActivity(intent); + return true; + } else { + return false; + } + } +} diff --git a/app/src/main/java/com/vectras/vm/utils/ZipUtils.java b/app/src/main/java/com/vectras/vm/utils/ZipUtils.java index 946dc8d..444e2e6 100644 --- a/app/src/main/java/com/vectras/vm/utils/ZipUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/ZipUtils.java @@ -14,9 +14,11 @@ import com.vectras.vm.R; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.Enumeration; import java.util.zip.CRC32; import java.util.zip.ZipEntry; @@ -258,64 +260,10 @@ public class ZipUtils { ProgressBar progressBar ) { try { - long totalBytes = 0; - for (String path : filePaths) { - File f = new File(path); - if (f.isFile()) totalBytes += f.length(); - } - - long bytesWritten = 0; - byte[] buffer; - try (FileOutputStream fos = new FileOutputStream(outputZip); ZipOutputStream zos = new ZipOutputStream(fos)) { - for (String filePath : filePaths) { - File file = new File(filePath); - long size = file.length(); - long crc = calculateCrc(context, file); - - try (FileInputStream fis = new FileInputStream(file)) { - ZipEntry entry = new ZipEntry(file.getName()); - - entry.setMethod(ZipEntry.DEFLATED); - entry.setSize(size); - - if (MainSettingsManager.getCyclicRedundancyCheck(context)) - entry.setCrc(crc); - - zos.putNextEntry(entry); - - if (DeviceUtils.totalMemoryCapacity(context) < 4L * 1024 * 1024 * 1024) - buffer = new byte[64 * 1024]; - else - buffer = new byte[128 * 1024]; - - int len; - long lastProgress = -1; - while ((len = fis.read(buffer)) != -1) { - zos.write(buffer, 0, len); - bytesWritten += len; - - final int progress = (int) ((bytesWritten * 100L) / totalBytes); - - if (progress > lastProgress) { - lastProgress = progress; - updateStatus( - statusTextView, - progressBar, - (progress == 0 || progress > 100 ? - context.getString(R.string.exporting) : - context.getString(R.string.completed) + " " + progress + "%") - + "\n" + context.getString(R.string.please_stay_here), - progress - ); - } - } - - zos.closeEntry(); - } - } + compressCore(context, filePaths, zos, statusTextView, progressBar); } return true; } catch (Exception e) { @@ -325,6 +273,91 @@ public class ZipUtils { } } + public static boolean compress( + Context context, + String[] filePaths, + Uri outputZip, + TextView statusTextView, + ProgressBar progressBar + ) { + try { + try (OutputStream os = context.getContentResolver().openOutputStream(outputZip); + ZipOutputStream zos = new ZipOutputStream(os)) { + + compressCore(context, filePaths, zos, statusTextView, progressBar); + } + return true; + } catch (Exception e) { + Log.e(TAG, "compress: ", e); + lastErrorContent = e.toString(); + return false; + } + } + + public static void compressCore( + Context context, + String[] filePaths, + ZipOutputStream zos, + TextView statusTextView, + ProgressBar progressBar) throws Exception { + + long totalBytes = 0; + for (String path : filePaths) { + File f = new File(path); + if (f.isFile()) totalBytes += f.length(); + } + + long bytesWritten = 0; + byte[] buffer; + + for (String filePath : filePaths) { + File file = new File(filePath); + long size = file.length(); + long crc = calculateCrc(context, file); + + try (FileInputStream fis = new FileInputStream(file)) { + ZipEntry entry = new ZipEntry(file.getName()); + + entry.setMethod(ZipEntry.DEFLATED); + entry.setSize(size); + + if (MainSettingsManager.getCyclicRedundancyCheck(context)) + entry.setCrc(crc); + + zos.putNextEntry(entry); + + if (DeviceUtils.totalMemoryCapacity(context) < 4L * 1024 * 1024 * 1024) + buffer = new byte[64 * 1024]; + else + buffer = new byte[128 * 1024]; + + int len; + long lastProgress = -1; + while ((len = fis.read(buffer)) != -1) { + zos.write(buffer, 0, len); + bytesWritten += len; + + final int progress = (int) ((bytesWritten * 100L) / totalBytes); + + if (progress > lastProgress) { + lastProgress = progress; + updateStatus( + statusTextView, + progressBar, + (totalBytes > 0 && (progress == 0 || progress > 100) ? + context.getString(R.string.exporting) : + context.getString(R.string.completed) + " " + progress + "%") + + "\n" + context.getString(R.string.please_stay_here), + progress + ); + } + } + + zos.closeEntry(); + } + } + } + private static void updateStatus(TextView statusTextView, ProgressBar progressbar, String msg, int progress) { if (!(statusTextView == null || statusTextView.getContext() == null)) { ((Activity) statusTextView.getContext()).runOnUiThread(() -> statusTextView.setText(msg)); diff --git a/app/src/main/java/com/vectras/vm/view/GithubUserView.java b/app/src/main/java/com/vectras/vm/view/GithubUserView.java index b2f5fe3..1f6bdb9 100644 --- a/app/src/main/java/com/vectras/vm/view/GithubUserView.java +++ b/app/src/main/java/com/vectras/vm/view/GithubUserView.java @@ -2,22 +2,20 @@ package com.vectras.vm.view; import android.app.Activity; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; -import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import android.widget.Button; + +import androidx.annotation.NonNull; import com.bumptech.glide.Glide; import com.vectras.vm.R; import com.vectras.vm.model.GithubUser; import com.vectras.vm.network.GithubApiService; +import com.vectras.vm.utils.IntentUtils; import retrofit2.Call; import retrofit2.Callback; @@ -73,7 +71,7 @@ public class GithubUserView extends LinearLayout { Call call = service.getUser(username); call.enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(@NonNull Call call, @NonNull Response response) { if (response.isSuccessful() && response.body() != null) { GithubUser user = response.body(); thisUserNameGitHub = user.getLogin(); @@ -95,7 +93,7 @@ public class GithubUserView extends LinearLayout { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(@NonNull Call call, @NonNull Throwable t) { userName.setText(getContext().getString(R.string.unknow)); userDescription.setText(getContext().getString(R.string.unknow)); profileImage.setImageResource(R.drawable.account_circle_24px); @@ -104,8 +102,6 @@ public class GithubUserView extends LinearLayout { } private void openGithubProfile(Context context) { - String url = "https://github.com/" + thisUserNameGitHub; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - context.startActivity(intent); + IntentUtils.openUrl(context, "https://github.com/" + thisUserNameGitHub, true); } } \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vterm/Terminal.java b/app/src/main/java/com/vectras/vterm/Terminal.java index 1b26a27..c97dc0b 100644 --- a/app/src/main/java/com/vectras/vterm/Terminal.java +++ b/app/src/main/java/com/vectras/vterm/Terminal.java @@ -19,10 +19,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -30,6 +26,7 @@ import com.vectras.vm.R; import com.vectras.vm.VMManager; import com.vectras.vm.AppConfig; import com.vectras.vm.VectrasApp; +import com.vectras.vm.logger.VectrasStatus; import com.vectras.vm.utils.ClipboardUltils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.NotificationUtils; @@ -63,18 +60,23 @@ public class Terminal { AtomicReference output = new AtomicReference<>(new StringBuilder()); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); - com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + userCommand + ""); + VectrasStatus.logError("VTERM: >" + userCommand + ""); // Show ProgressDialog - View progressView = LayoutInflater.from(dialogActivity).inflate(R.layout.dialog_progress_style, null); - TextView progress_text = progressView.findViewById(R.id.progress_text); - progress_text.setText(progressDialogMessage); - AlertDialog progressDialog = new MaterialAlertDialogBuilder(dialogActivity, R.style.CenteredDialogTheme) - .setView(progressView) - .setCancelable(false) - .create(); + AlertDialog progressDialog; + if (dialogActivity != null) { + View progressView = LayoutInflater.from(dialogActivity).inflate(R.layout.dialog_progress_style, null); + TextView progress_text = progressView.findViewById(R.id.progress_text); + progress_text.setText(progressDialogMessage); + progressDialog = new MaterialAlertDialogBuilder(dialogActivity, R.style.CenteredDialogTheme) + .setView(progressView) + .setCancelable(false) + .create(); - if (showProgressDialog) progressDialog.show(); + if (showProgressDialog) progressDialog.show(); + } else { + progressDialog = null; + } new Thread(() -> { try { @@ -116,17 +118,18 @@ public class Terminal { output.set(streamLog(userCommand, qemuProcess, false)); } catch (IOException e) { - progressDialog.dismiss(); // Dismiss ProgressDialog output.get().append(e.getMessage()); errors.append(Log.getStackTraceString(e)); } finally { new Handler(Looper.getMainLooper()).post(() -> { - progressDialog.dismiss(); // Dismiss ProgressDialog AppConfig.temporaryLastedTerminalOutput = output.toString(); - if (showResultDialog) { - String finalOutput = output.toString(); - String finalErrors = errors.toString(); - showDialog(finalOutput.isEmpty() ? finalErrors : finalOutput.replace("read interrupted", "Done!"), dialogActivity, userCommand); + if (dialogActivity != null) { + progressDialog.dismiss(); // Dismiss ProgressDialog + if (showResultDialog) { + String finalOutput = output.toString(); + String finalErrors = errors.toString(); + showDialog(finalOutput.isEmpty() ? finalErrors : finalOutput.replace("read interrupted", "Done!"), dialogActivity, userCommand); + } } }); } @@ -137,7 +140,7 @@ public class Terminal { AtomicReference output = new AtomicReference<>(new StringBuilder()); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); - com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + userCommand + ""); + VectrasStatus.logError("VTERM: >" + userCommand + ""); new Thread(() -> { try { // Set up the qemuProcess builder to start PRoot with environmental variables and commands @@ -185,7 +188,7 @@ public class Terminal { processBuilder.command(prootCommand); qemuProcess = processBuilder.start(); - output.set(streamLog(userCommand, qemuProcess, false)); + output.set(streamLog(userCommand, qemuProcess, true)); } catch (IOException e) { output.get().append(e.getMessage()); errors.append(Log.getStackTraceString(e)); @@ -210,7 +213,7 @@ public class Terminal { StringBuilder output = new StringBuilder(); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); - com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + userCommand + ""); + VectrasStatus.logError("VTERM: >" + userCommand + ""); try { ProcessBuilder processBuilder = new ProcessBuilder(); @@ -261,11 +264,11 @@ public class Terminal { void onCommandCompleted(String output, String errors); } - public String executeShellCommand(String userCommand, Context dialogActivity, boolean isShowProgressDialog, CommandCallback callback) { + public void executeShellCommand(String userCommand, Context dialogActivity, boolean isShowProgressDialog, CommandCallback callback) { AtomicReference output = new AtomicReference<>(new StringBuilder()); StringBuilder errors = new StringBuilder(); Log.d(TAG, userCommand); - com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + userCommand + ""); + VectrasStatus.logError("VTERM: >" + userCommand + ""); // Show ProgressDialog on the main thread View progressView = LayoutInflater.from(dialogActivity).inflate(R.layout.dialog_progress_style, null); @@ -330,8 +333,6 @@ public class Terminal { new Handler(Looper.getMainLooper()).post(() -> callback.onCommandCompleted(output.toString(), errors.toString())); } }).start(); - - return "Execution is in progress..."; // Returning a message indicating the command execution is ongoing } /** @@ -357,7 +358,7 @@ public class Terminal { return false; } - public static StringBuilder streamLog(String command, Process process, boolean isShortProcess) { + public static StringBuilder streamLog(String command, Process process, boolean isShowResultCode) { StringBuilder output = new StringBuilder(); try { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); @@ -371,23 +372,29 @@ public class Terminal { String line; while ((line = reader.readLine()) != null) { - com.vectras.vm.logger.VectrasStatus.logError("VTERM: >" + line + ""); + VectrasStatus.logError("VTERM: >" + line + ""); output.append(line).append("\n"); } while ((line = errorReader.readLine()) != null) { Log.w(TAG, line); - com.vectras.vm.logger.VectrasStatus.logError("VTERM ERROR: >" + line + ""); + VectrasStatus.logError("VTERM ERROR: >" + line + ""); output.append(line).append("\n"); } - if (isShortProcess) { - int exitCode = process.waitFor(); - if (exitCode == 0) { - output.append("Execution finished successfully.\n"); - } else { - output.append("Execution finished with exit code: ").append(exitCode).append("\n"); + if (isShowResultCode) { + new Thread(() -> { + int exitCode; + try { + exitCode = process.waitFor(); + if (exitCode == 0) { + output.append("\nExecution finished successfully.\n"); + } else { + output.append("\nExecution finished with exit code: ").append(exitCode).append("\n"); + } + } catch (Exception ignored) { } + }).start(); } reader.close(); diff --git a/app/src/main/res/layout/activity_qemu_params_editor.xml b/app/src/main/res/layout/activity_qemu_params_editor.xml index 460cbe4..508e062 100644 --- a/app/src/main/res/layout/activity_qemu_params_editor.xml +++ b/app/src/main/res/layout/activity_qemu_params_editor.xml @@ -6,7 +6,7 @@ xmlns:tools="http://schemas.android.com/tools" android:fitsSystemWindows="true" android:id="@+id/main" - tools:context=".QemuParamsEditorActivity"> + tools:context=".creator.QemuParamsEditorActivity"> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycler_view.xml b/app/src/main/res/layout/recycler_view.xml deleted file mode 100644 index 017a005..0000000 --- a/app/src/main/res/layout/recycler_view.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/simple_layout_list_view_with_check.xml b/app/src/main/res/layout/simple_layout_list_view_with_check.xml index beb9771..80e6ba9 100644 --- a/app/src/main/res/layout/simple_layout_list_view_with_check.xml +++ b/app/src/main/res/layout/simple_layout_list_view_with_check.xml @@ -3,22 +3,20 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" - android:paddingVertical="16dp" - android:paddingHorizontal="24dp" + android:padding="16dp" android:id="@+id/main" android:background="?attr/selectableItemBackground"> - - + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9d79145..d7c8095 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -508,6 +508,8 @@ Hard disk Floppy disk Network + Rom successfully exported. + Options diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index 8fb8892..87f5791 100644 --- a/web/data/UpdateConfig.json +++ b/web/data/UpdateConfig.json @@ -5,11 +5,11 @@ "url": "https://github.com/xoureldeen/Vectras-VM-Android/releases", "Message": "

3.6.0

\nBugs fixed.", "cancellable": true, - "versionCodeBeta":"70", - "versionNameBeta":"3.6.6", - "versionNameBetas":"3.0.0,3.1.0,3.2.1,3.2.2,3.2.3,3.2.4,3.2.5,3.2.6,3.2.7,3.2.8,3.2.9,3.2.10,3.3.1,3.3.2,3.3.3,3.3.4,3.3.5,3.3.6,3.3.7,3.3.8,3.3.9,3.4.1,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8,3.4.9,3.5.1,3.5.2,3.5.3,3.5.4,3.5.5,3.5.6,3.5.7,3.5.8,3.5.9,3.6.1,3.6.2,3.6.3,3.6.4,3.6.5,3.6.6", + "versionCodeBeta":"71", + "versionNameBeta":"3.6.7", + "versionNameBetas":"3.0.0,3.1.0,3.2.1,3.2.2,3.2.3,3.2.4,3.2.5,3.2.6,3.2.7,3.2.8,3.2.9,3.2.10,3.3.1,3.3.2,3.3.3,3.3.4,3.3.5,3.3.6,3.3.7,3.3.8,3.3.9,3.4.1,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8,3.4.9,3.5.1,3.5.2,3.5.3,3.5.4,3.5.5,3.5.6,3.5.7,3.5.8,3.5.9,3.6.1,3.6.2,3.6.3,3.6.4,3.6.5,3.6.6,3.6.7", "sizeBeta": "43 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

3.6.6

Bugs fixed.", + "MessageBeta": "

3.6.7

Bugs fixed.", "cancellableBeta": true }