diff --git a/app/build.gradle b/app/build.gradle index 6c09470..853a2b3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi - versionCode 102 - versionName "3.9.8" + versionCode 103 + versionName "3.9.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true diff --git a/app/src/main/java/com/vectras/qemu/MainSettingsManager.java b/app/src/main/java/com/vectras/qemu/MainSettingsManager.java index 07bde3d..cc93dff 100644 --- a/app/src/main/java/com/vectras/qemu/MainSettingsManager.java +++ b/app/src/main/java/com/vectras/qemu/MainSettingsManager.java @@ -361,13 +361,13 @@ public class MainSettingsManager extends AppCompatActivity }); } -// if (Objects.equals(getArch(activity), "I386")) { // I386 DOES NOT SUPPORT SHARED FOLDER -// SwitchPreferenceCompat sharedPref = findPreference("sharedFolder"); -// sharedPref.setEnabled(false); -// sharedPref.setChecked(false); -// setSharedFolder(activity, false); -// -// } + /*if (Objects.equals(getArch(activity), "I386")) { // I386 DOES NOT SUPPORT SHARED FOLDER + SwitchPreferenceCompat sharedPref = findPreference("sharedFolder"); + sharedPref.setEnabled(false); + sharedPref.setChecked(false); + setSharedFolder(activity, false); + + } if (!getuseDefaultBios(getActivity())) { SwitchPreferenceCompat useUEFIPref = findPreference("useUEFI"); @@ -398,7 +398,7 @@ public class MainSettingsManager extends AppCompatActivity } } return true; - }); + });*/ } private void onMemory() { diff --git a/app/src/main/java/com/vectras/qemu/MainVNCActivity.java b/app/src/main/java/com/vectras/qemu/MainVNCActivity.java index e17f43a..b3bc7e9 100644 --- a/app/src/main/java/com/vectras/qemu/MainVNCActivity.java +++ b/app/src/main/java/com/vectras/qemu/MainVNCActivity.java @@ -58,16 +58,15 @@ import com.vectras.vm.databinding.DesktopControlsBinding; import com.vectras.vm.databinding.GameControlsBinding; import com.vectras.vm.databinding.SendKeyDialogBinding; import com.vectras.vm.manager.QmpSender; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.manager.VmControllerDialog; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.ListUtils; -import com.vectras.vm.utils.NetworkUtils; import com.vectras.vm.utils.SimulateKeyEvent; import com.vectras.vm.utils.StreamAudio; import com.vectras.vm.utils.UIUtils; -import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Objects; @@ -173,7 +172,7 @@ public class MainVNCActivity extends VncCanvasActivity { ConnectionBean.useLocalCursor = MainSettingsManager.getShowVirtualMouse(this) || VMManager.isNeedUseVirtualMouse(); streamAudio = new StreamAudio(this); - streamAudio.setFile(AppConfig.vmFolder + Config.vmID + "/audio.raw"); + streamAudio.setFile(VmFileManager.getAudioRaw(this, Config.vmID)); } private void setDefaulViewMode() { @@ -730,20 +729,6 @@ public class MainVNCActivity extends VncCanvasActivity { showPanningState(); } - public void promptPause(final Activity activity) { - final AlertDialog alertDialog; - alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create(); - alertDialog.setTitle("Pause VM"); - TextView stateView = new TextView(activity); - stateView.setText("This make take a while depending on the RAM size used"); - stateView.setPadding(20, 20, 20, 20); - alertDialog.setView(stateView); - - alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Pause", (dialog, which) -> onPauseVM()); - alertDialog.show(); - - } - @Override public void onBackPressed() { super.onBackPressed(); @@ -780,7 +765,7 @@ public class MainVNCActivity extends VncCanvasActivity { this.vncCanvas.setFocusableInTouchMode(true); // syncCursorViewWithBitmap(); - streamAudio.play(); + if (!streamAudio.isPlaying()) streamAudio.play(); }); } diff --git a/app/src/main/java/com/vectras/vm/CqcmActivity.java b/app/src/main/java/com/vectras/vm/CqcmActivity.java index 8730d75..bc15aa4 100644 --- a/app/src/main/java/com/vectras/vm/CqcmActivity.java +++ b/app/src/main/java/com/vectras/vm/CqcmActivity.java @@ -16,6 +16,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.vectras.vm.main.MainActivity; import com.vectras.vm.main.core.PendingCommand; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.JSONUtils; import com.vectras.vm.utils.PermissionUtils; @@ -98,7 +99,7 @@ public class CqcmActivity extends AppCompatActivity { Toast.makeText(getApplicationContext(), getString(R.string.an_error_occurred_and_vm_was_not_created), Toast.LENGTH_LONG).show(); } } - FileUtils.writeToFile(AppConfig.vmFolder + vmId, "cqcm.json", getIntent().getStringExtra("cqcmcontent")); + FileUtils.writeToFile(VmFileManager.getPath(vmID), "cqcm.json", getIntent().getStringExtra("cqcmcontent")); } else { Toast.makeText(getApplicationContext(), "An error occurred and it was not possible to create or edit a virtual machine.", Toast.LENGTH_LONG).show(); } diff --git a/app/src/main/java/com/vectras/vm/ExportRomActivity.java b/app/src/main/java/com/vectras/vm/ExportRomActivity.java index c06a4fa..18f5b9e 100644 --- a/app/src/main/java/com/vectras/vm/ExportRomActivity.java +++ b/app/src/main/java/com/vectras/vm/ExportRomActivity.java @@ -21,6 +21,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.gson.Gson; import com.vectras.vm.databinding.ActivityExportRomBinding; import com.vectras.vm.main.vms.DataMainRoms; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.PackageUtils; @@ -114,7 +115,7 @@ public class ExportRomActivity extends AppCompatActivity { } } - String getRomPath = AppConfig.vmFolder + current.vmID + "/"; + String getRomPath = VmFileManager.getPath(current.vmID); HashMap vmConfigMap = new HashMap<>(); vmConfigMap.put("title", current.itemName); @@ -143,7 +144,7 @@ public class ExportRomActivity extends AppCompatActivity { vmConfigMap.put("isShowBootMenu", current.isShowBootMenu); vmConfigMap.put("isUseUefi", current.isUseUefi); vmConfigMap.put("isUseLocalTime", current.isUseLocalTime); - vmConfigMap.put("qemu", current.itemExtra.replace(getRomPath, "OhnoIjustrealizeditsmidnightandIstillhavetodothis")); + vmConfigMap.put("qemu", VmFileManager.pathToTextMark(current.vmID, current.itemExtra)); vmConfigMap.put("arch", current.itemArch); if (Objects.requireNonNull(binding.edAuthor.getText()).toString().isEmpty()) { @@ -166,7 +167,7 @@ public class ExportRomActivity extends AppCompatActivity { String[] filePaths = new String[0]; ArrayList _filelist = new ArrayList<>(); - FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder + current.vmID, _filelist); + FileUtils.getAListOfAllFilesAndFoldersInADirectory(VmFileManager.getPath(current.vmID), _filelist); if (!_filelist.isEmpty()) { ArrayList pathList = new ArrayList<>(); @@ -176,18 +177,18 @@ public class ExportRomActivity extends AppCompatActivity { if (_filelist.get(_repeat).endsWith("rom-data.json")) { pathList.add(tempFolder + "rom-data.json"); - } else if (_filelist.get(_repeat).endsWith("snapshot.sh")) { - if (FileUtils.isFileExists(AppConfig.vmFolder + current.vmID + "/snapshot.bin")) { + } else if (_filelist.get(_repeat).endsWith(VmFileManager.SNAPSHOT_SH_FILE_NAME)) { + if (VmFileManager.isSnapshotBinExists(current.vmID)) { String snapshotParams = FileUtils.readAFile(_filelist.get(_repeat)); snapshotParams = StartVM.removeQmpParams(snapshotParams); snapshotParams = StartVM.removeDisplayParams(snapshotParams); - FileUtils.writeToFile(tempFolder, "snapshot.sh", snapshotParams.replace(getRomPath, "OhnoIjustrealizeditsmidnightandIstillhavetodothis")); - pathList.add(tempFolder + "snapshot.sh"); + FileUtils.writeToFile(tempFolder, VmFileManager.SNAPSHOT_SH_FILE_NAME, snapshotParams.replace(getRomPath, VmFileManager.TEXT_MARK_VM_PATH)); + pathList.add(tempFolder + VmFileManager.SNAPSHOT_SH_FILE_NAME); } - } else if (_filelist.get(_repeat).endsWith("cqcm.json")) { - FileUtils.writeToFile(tempFolder, "cqcm.json", FileUtils.readAFile(_filelist.get(_repeat)).replace(getRomPath, "OhnoIjustrealizeditsmidnightandIstillhavetodothis")); - pathList.add(tempFolder + "cqcm.json"); - } else if (_filelist.get(_repeat).endsWith("screenshot.ppm") || _filelist.get(_repeat).endsWith("screenshot.png") || _filelist.get(_repeat).endsWith("audio.raw")) { + } else if (_filelist.get(_repeat).endsWith(VmFileManager.CREATE_COMMAND_CONFIG_FILE_NAME)) { + FileUtils.writeToFile(tempFolder, VmFileManager.CREATE_COMMAND_CONFIG_FILE_NAME, FileUtils.readAFile(_filelist.get(_repeat)).replace(getRomPath, VmFileManager.TEXT_MARK_VM_PATH)); + pathList.add(tempFolder + VmFileManager.CREATE_COMMAND_CONFIG_FILE_NAME); + } else if (_filelist.get(_repeat).endsWith(VmFileManager.SCREENSHOT_PNG_FILE_NAME) || _filelist.get(_repeat).endsWith(VmFileManager.AUDIO_STREAM_FILE_NAME)) { //ignore } else { pathList.add(_filelist.get(_repeat)); diff --git a/app/src/main/java/com/vectras/vm/StartVM.java b/app/src/main/java/com/vectras/vm/StartVM.java index fdd62e0..30a55ed 100644 --- a/app/src/main/java/com/vectras/vm/StartVM.java +++ b/app/src/main/java/com/vectras/vm/StartVM.java @@ -9,9 +9,9 @@ import com.vectras.qemu.MainSettingsManager; import com.vectras.qemu.utils.RamInfo; import com.vectras.vm.creator.VMCreatorSelector; import com.vectras.vm.main.vms.DataMainRoms; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.setupwizard.SetupFeatureCore; import com.vectras.vm.utils.FileUtils; -import com.vectras.vm.utils.TextUtils; import java.io.File; import java.util.ArrayList; @@ -25,8 +25,8 @@ public class StartVM { public static String env(Activity activity, DataMainRoms vmData) { vmConfigs = vmData; - if (VMManager.isNeedLoadMigrate() && FileUtils.isFileExists(AppConfig.vmFolder + Config.vmID + "/snapshot.sh")) { - String snapshotParams = FileUtils.readAFile(AppConfig.vmFolder + Config.vmID + "/snapshot.sh").replace("\n", ""); + if (VMManager.isNeedLoadMigrate() && FileUtils.isFileExists(VmFileManager.getSnapshotSh(Config.vmID))) { + String snapshotParams = FileUtils.readAFile(VmFileManager.getSnapshotSh(Config.vmID)).replace("\n", ""); if (VMManager.isthiscommandsafe(snapshotParams, activity)) { snapshotParams = removeQemuSystem(snapshotParams); snapshotParams = removeQmpParams(snapshotParams); diff --git a/app/src/main/java/com/vectras/vm/VMManager.java b/app/src/main/java/com/vectras/vm/VMManager.java index bf69cc6..c3d6968 100644 --- a/app/src/main/java/com/vectras/vm/VMManager.java +++ b/app/src/main/java/com/vectras/vm/VMManager.java @@ -1,65 +1,38 @@ package com.vectras.vm; -import static android.content.Intent.ACTION_OPEN_DOCUMENT; import static com.vectras.vm.utils.FileUtils.isFileExists; import static java.lang.Thread.sleep; -import android.androidVNC.ConnectionBean; -import android.androidVNC.VncCanvasActivity; import android.app.Activity; -import android.app.NotificationManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.fragment.app.FragmentActivity; -import com.anbui.elephant.retrofit2utils.Retrofit2Utils; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.textfield.TextInputLayout; import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import com.vectras.qemu.Config; import com.vectras.qemu.MainSettingsManager; -import com.vectras.qemu.MainVNCActivity; -import com.vectras.qemu.QMPClient; -import com.vectras.qemu.VNCConfig; import com.vectras.qemu.utils.QmpClient; import com.vectras.vm.main.MainActivity; import com.vectras.vm.main.core.MainStartVM; import com.vectras.vm.main.vms.DataMainRoms; -import com.vectras.vm.manager.QemuConsoleDialog; import com.vectras.vm.manager.QmpSender; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.manager.VmActions; -import com.vectras.vm.settings.VNCSettingsActivity; import com.vectras.vm.settings.X11DisplaySettingsActivity; -import com.vectras.vm.setupwizard.SetupFeatureCore; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.JSONUtils; -import com.vectras.vm.utils.NotificationUtils; import com.vectras.vm.utils.ProgressDialog; import com.vectras.vm.utils.TextUtils; import com.vectras.vterm.Terminal; @@ -237,7 +210,7 @@ public class VMManager { } public static boolean hideVM(String vmId) { - return FileUtils.rename(AppConfig.vmFolder + vmId, "_" + vmId); + return FileUtils.rename(VmFileManager.getPath(vmId), "_" + vmId); } public static boolean unHideVM(String vmPath) { @@ -344,16 +317,16 @@ public class VMManager { if (isKeepFiles) { isCompleted = hideVM(vmId); if (isCompleted && isVmFilesInUse(vmId, vmList)) { - vmList = vmList.replace(AppConfig.vmFolder + vmId, AppConfig.vmFolder + "_" + vmId); + vmList = VmFileManager.replaceToHide(vmId, vmList); } } else { if (isVmFilesInUse(vmId, vmList)) { isKeptSomeFiles = true; isCompleted = hideVM(vmId); if (isCompleted) - vmList = vmList.replace(AppConfig.vmFolder + vmId, AppConfig.vmFolder + "_" + vmId); + vmList = VmFileManager.replaceToHide(vmId, vmList); } else { - isCompleted = FileUtils.delete(new File(AppConfig.vmFolder + vmId)); + isCompleted = VmFileManager.delete(vmId); } } @@ -383,8 +356,8 @@ public class VMManager { String finalvmList = new Gson().toJson(arr); for (int i = 0; i < restoredVms.size(); i++) { - if (finalvmList.contains(AppConfig.vmFolder + "_" + restoredVms.get(i))) { - finalvmList = finalvmList.replace(AppConfig.vmFolder + "_" + restoredVms.get(i), AppConfig.vmFolder + restoredVms.get(i)); + if (finalvmList.contains(VmFileManager.getPathHide(restoredVms.get(i)))) { + finalvmList = VmFileManager.replaceToShow(restoredVms.get(i), finalvmList); } } @@ -416,7 +389,7 @@ public class VMManager { } public static boolean isVmFilesInUse(String vmId, String vmList) { - File[] files = new File(AppConfig.vmFolder + vmId).listFiles(); + File[] files = new File(VmFileManager.quickGetPath(vmId)).listFiles(); if (files == null) return false; for (File f : files) { if (vmList.contains(f.getAbsolutePath())) { @@ -858,7 +831,7 @@ public class VMManager { } public static String startMigrate() { - return sendQMPCommand("migrate \\\"exec:cat > " + AppConfig.vmFolder + Config.vmID + "/snapshot.bin\\\""); + return sendQMPCommand("migrate \\\"exec:cat > " + VmFileManager.getSnapshotBin(Config.vmID) + "\\\""); } public static Boolean[] getMigrateStatus() { @@ -871,15 +844,15 @@ public class VMManager { } public static String loadMigrate() { - return sendQMPCommand("migrate_incoming \\\"exec:cat " + AppConfig.vmFolder + Config.vmID + "/snapshot.bin\\\""); + return sendQMPCommand("migrate_incoming \\\"exec:cat " + VmFileManager.getSnapshotBin(Config.vmID) + "\\\""); } public static boolean isNeedLoadMigrate() { - return isFileExists(AppConfig.vmFolder + Config.vmID + "/snapshot.bin"); + return isFileExists(VmFileManager.getSnapshotBin(Config.vmID)); } public static boolean deleteMigrate() { - return FileUtils.delete(new File(AppConfig.vmFolder + Config.vmID + "/snapshot.bin")); + return FileUtils.delete(new File(VmFileManager.getSnapshotBin(Config.vmID))); } public static boolean hideMigrateFile() { @@ -1120,7 +1093,7 @@ public class VMManager { } public static String addAudioDevWav(String vmID, String env) { - final String audioDevParam = ",audiodev=snd0 -audiodev wav,id=snd0,path=" + AppConfig.vmFolder + vmID + "/audio.raw "; + final String audioDevParam = ",audiodev=snd0 -audiodev wav,id=snd0,out.frequency=48000,path=" + VmFileManager.getAudioRaw(VectrasApp.getContext(), vmID); String result = env; if (env.startsWith("-device hda-duplex ") || env.contains(" -device hda-duplex ") || env.endsWith(" -device hda-duplex")) { result = result.replaceFirst(" -device hda-duplex", " -device hda-duplex" + audioDevParam); 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 0f046fe..e7cd3b3 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java @@ -35,6 +35,7 @@ import com.vectras.vm.main.vms.DataMainRoms; import com.vectras.vm.databinding.ActivityVmCreatorBinding; import com.vectras.vm.databinding.DialogProgressStyleBinding; import com.vectras.vm.main.MainActivity; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.utils.ClipboardUltils; import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; @@ -88,8 +89,7 @@ public class VMCreatorActivity extends AppCompatActivity { filePicker.launch("*/*"); return true; } else if (id == R.id.show_in_folder) { - FileUtils.createDirectory(AppConfig.vmFolder + vmID); - FileUtils.openFolder(this, AppConfig.vmFolder + vmID); + FileUtils.openFolder(this, VmFileManager.getPath(vmID)); return true; } else { return super.onOptionsItemSelected(item); @@ -131,7 +131,7 @@ public class VMCreatorActivity extends AppCompatActivity { binding.driveField.setEndIconOnClickListener(v -> { if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) { CreateImageDialogFragment dialogFragment = new CreateImageDialogFragment(); - dialogFragment.folder = AppConfig.vmFolder + vmID + "/"; + dialogFragment.folder = VmFileManager.getPath(vmID); dialogFragment.customRom = true; dialogFragment.filename = Objects.requireNonNull(binding.title.getText()).toString(); dialogFragment.drive = binding.drive; @@ -148,7 +148,7 @@ public class VMCreatorActivity extends AppCompatActivity { true, () -> diskPicker.launch("*/*"), () -> { - if (binding.drive.getText().toString().contains(AppConfig.vmFolder + vmID)) { + if (binding.drive.getText().toString().contains(VmFileManager.quickGetPath(vmID))) { FileUtils.delete(new File(Objects.requireNonNull(binding.drive.getText()).toString())); } binding.drive.setText(""); @@ -275,7 +275,7 @@ public class VMCreatorActivity extends AppCompatActivity { if (Objects.requireNonNull(getIntent().getStringExtra("romextra")).isEmpty()) { setDefault(); } else { - binding.qemu.setText(Objects.requireNonNull(getIntent().getStringExtra("romextra")).replaceAll("OhnoIjustrealizeditsmidnightandIstillhavetodothis", AppConfig.vmFolder + vmID + "/")); + binding.qemu.setText(VmFileManager.textMarkToPath(vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra")))); } binding.title.setText(getIntent().getStringExtra("romname")); @@ -296,7 +296,7 @@ public class VMCreatorActivity extends AppCompatActivity { selectedDiskFile(Uri.fromFile(new File((Objects.requireNonNull(getIntent().getStringExtra("rompath"))))), false); } if (!Objects.requireNonNull(getIntent().getStringExtra("addtodrive")).isEmpty()) { - binding.drive.setText(AppConfig.vmFolder + vmID + "/" + getIntent().getStringExtra("romfilename")); + binding.drive.setText(VmFileManager.getPath(vmID, getIntent().getStringExtra("romfilename"))); if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) { binding.driveField.setEndIconDrawable(R.drawable.add_24px); } else { @@ -315,8 +315,8 @@ public class VMCreatorActivity extends AppCompatActivity { if (MainSettingsManager.autoCreateDisk(this)) { if (createVMFolder(true)) { Terminal vterm = new Terminal(this); - vterm.executeShellCommand2("qemu-img create -f qcow2 " + AppConfig.vmFolder + vmID + "/disk.qcow2 128G", false, this); - binding.drive.setText(AppConfig.vmFolder + vmID + "/disk.qcow2"); + vterm.executeShellCommand2("qemu-img create -f qcow2 " + VmFileManager.getPath(vmID, "disk.qcow2") + " 128G", false, this); + binding.drive.setText(VmFileManager.getPath(vmID, "disk.qcow2")); } } else { binding.driveField.setEndIconDrawable(R.drawable.add_24px); @@ -325,7 +325,7 @@ public class VMCreatorActivity extends AppCompatActivity { } } - if (PackageUtils.getVersionCode("com.anbui.cqcm.app", this) < 735 || !FileUtils.isFileExists(AppConfig.vmFolder + vmID + "/cqcm.json")) { + if (PackageUtils.getVersionCode("com.anbui.cqcm.app", this) < 735 || !FileUtils.isFileExists(VmFileManager.getCreateCommandConfigFile(vmID))) { binding.opencqcm.setVisibility(View.GONE); } else { binding.opencqcm.setOnClickListener(v -> { @@ -333,7 +333,7 @@ public class VMCreatorActivity extends AppCompatActivity { Intent intentcqcm = new Intent(); intentcqcm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intentcqcm.setComponent(new ComponentName("com.anbui.cqcm.app", "com.anbui.cqcm.app.DownloadActivity")); - intentcqcm.putExtra("content", FileUtils.readAFile(AppConfig.vmFolder + vmID + "/cqcm.json")); + intentcqcm.putExtra("content", FileUtils.readAFile(VmFileManager.getCreateCommandConfigFile(vmID))); intentcqcm.putExtra("vectrasVMId", vmID); startActivity(intentcqcm); finish(); @@ -368,7 +368,7 @@ public class VMCreatorActivity extends AppCompatActivity { if (isProcessingFile) return; if (!created && !modify) { - new Thread(() -> FileUtils.delete(new File(AppConfig.vmFolder + vmID))).start(); + new Thread(() -> VmFileManager.delete(vmID)).start(); } modify = false; finish(); @@ -376,7 +376,7 @@ public class VMCreatorActivity extends AppCompatActivity { public void onDestroy() { if (!created && !modify) { - new Thread(() -> FileUtils.delete(new File(AppConfig.vmFolder + vmID))).start(); + new Thread(() -> VmFileManager.delete(vmID)).start(); } modify = false; super.onDestroy(); @@ -410,11 +410,11 @@ public class VMCreatorActivity extends AppCompatActivity { _filename = String.valueOf(System.currentTimeMillis()); } - FileUtils.copyFileFromUri(this, uri, AppConfig.vmFolder + vmID + "/" + _filename); + FileUtils.copyFileFromUri(this, uri, VmFileManager.getPath(vmID, _filename)); String final_filename = _filename; runOnUiThread(() -> { - binding.cdrom.setText(AppConfig.vmFolder + vmID + "/" + final_filename); + binding.cdrom.setText(VmFileManager.getPath(vmID, final_filename)); binding.cdromField.setEndIconMode(TextInputLayout.END_ICON_CUSTOM); binding.cdromField.setEndIconDrawable(R.drawable.close_24px); changeOnClickCdrom(); @@ -502,7 +502,7 @@ public class VMCreatorActivity extends AppCompatActivity { _filename = String.valueOf(System.currentTimeMillis()); } - String filePath = AppConfig.vmFolder + vmID + "/" + _filename; + String filePath = VmFileManager.getPath(vmID, _filename); FileUtils.copyFileFromUri(this, uri, filePath); @@ -548,7 +548,7 @@ public class VMCreatorActivity extends AppCompatActivity { } if (current.itemPath != null && !current.itemPath.isEmpty()) { - binding.drive.setText((current.itemPath.contains("/") ? "" : AppConfig.vmFolder + vmID + "/").concat(current.itemPath)); + binding.drive.setText((current.itemPath.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.itemPath)); } if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) { @@ -558,7 +558,7 @@ public class VMCreatorActivity extends AppCompatActivity { } if (current.imgCdrom != null && !current.imgCdrom.isEmpty()) { - binding.cdrom.setText((current.imgCdrom.contains("/") ? "" : AppConfig.vmFolder + vmID + "/").concat(current.imgCdrom)); + binding.cdrom.setText((current.imgCdrom.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.imgCdrom)); } if (!Objects.requireNonNull(binding.cdrom.getText()).toString().isEmpty()) { @@ -568,12 +568,12 @@ public class VMCreatorActivity extends AppCompatActivity { } if (current.itemIcon != null && !current.itemIcon.isEmpty()) { - thumbnailPath = (current.itemIcon.contains("/") ? "" : AppConfig.vmFolder + vmID + "/") + current.itemIcon; + thumbnailPath = (current.itemIcon.contains("/") ? "" : VmFileManager.getPath(vmID)) + current.itemIcon; thumbnailProcessing(); } if (current.itemExtra != null) { - binding.qemu.setText(current.itemExtra.replaceAll("OhnoIjustrealizeditsmidnightandIstillhavetodothis", AppConfig.vmFolder + vmID + "/")); + binding.qemu.setText(VmFileManager.textMarkToPath(vmID, current.itemExtra)); } bootFrom = current.bootFrom; @@ -627,7 +627,7 @@ public class VMCreatorActivity extends AppCompatActivity { } private boolean createVMFolder(boolean isShowDialog) { - File romDir = new File(AppConfig.vmFolder + vmID); + File romDir = new File(VmFileManager.getPath(vmID)); if (!romDir.exists()) { if (!romDir.mkdirs()) { if (isShowDialog) DialogUtils.oneDialog(this, @@ -734,9 +734,9 @@ public class VMCreatorActivity extends AppCompatActivity { executor.execute(() -> { try { isProcessingFile = true; - ImageUtils.convertToPng(this, uri, AppConfig.vmFolder + vmID + "/thumbnail.png"); + ImageUtils.convertToPng(this, uri, VmFileManager.getThumbnail(vmID)); - thumbnailPath = AppConfig.vmFolder + vmID + "/thumbnail.png"; + thumbnailPath = VmFileManager.getThumbnail(vmID); runOnUiThread(this::thumbnailProcessing); } catch (Exception e) { runOnUiThread(() -> DialogUtils.oneDialog(this, @@ -810,17 +810,17 @@ public class VMCreatorActivity extends AppCompatActivity { _filename = String.valueOf(System.currentTimeMillis()); } - FileUtils.copyFileFromUri(this, _content_describer, AppConfig.vmFolder + vmID + "/" + _filename); + FileUtils.copyFileFromUri(this, _content_describer, VmFileManager.getPath(vmID, _filename)); String final_filename = _filename; runOnUiThread(() -> { if ((isFinishing() || isDestroyed())) { if (!vmID.isEmpty()) - FileUtils.delete(new File(AppConfig.vmFolder + vmID + "/" + final_filename)); + FileUtils.delete(new File(VmFileManager.getPath(vmID, final_filename))); return; } if (_addtodrive) { - binding.drive.setText(AppConfig.vmFolder + vmID + "/" + final_filename); + binding.drive.setText(VmFileManager.getPath(vmID, final_filename)); binding.driveField.setEndIconDrawable(R.drawable.more_vert_24px); } }); @@ -923,19 +923,19 @@ public class VMCreatorActivity extends AppCompatActivity { showProgressDialog(getString(R.string.importing) + "\n" + getString(R.string.please_stay_here)); - Log.i(TAG, "importRom: Extracting with " + (isUseUri ? "uri" : "path") + " from " + filePath + " to " + AppConfig.vmFolder + vmID); + Log.i(TAG, "importRom: Extracting with " + (isUseUri ? "uri" : "path") + " from " + filePath + " to " + VmFileManager.getPath(vmID)); new Thread(() -> { boolean result = isUseUri ? ZipUtils.extract( this, fileUri, - AppConfig.vmFolder + vmID, + VmFileManager.getPath(vmID), dialogProgressStyleBinding.progressText, dialogProgressStyleBinding.progressBar ) : ZipUtils.extract( this, filePath, - AppConfig.vmFolder + vmID, + VmFileManager.getPath(vmID), dialogProgressStyleBinding.progressText, dialogProgressStyleBinding.progressBar ); @@ -944,7 +944,7 @@ public class VMCreatorActivity extends AppCompatActivity { DialogUtils.safeDismiss(this, progressDialog); if (isFinishing() || isDestroyed()) { - new Thread(() -> FileUtils.delete(new File(AppConfig.vmFolder + vmID))).start(); + new Thread(() -> VmFileManager.delete(vmID)).start(); return; } @@ -970,8 +970,8 @@ public class VMCreatorActivity extends AppCompatActivity { isProcessingFile = false; binding.ivIcon.setEnabled(true); try { - if (!FileUtils.isFileExists(AppConfig.vmFolder + vmID + "/rom-data.json")) { - String _getDiskFile = VMManager.quickScanDiskFileInFolder(AppConfig.vmFolder + vmID); + if (!VmFileManager.isConfigFileExists(vmID)) { + String _getDiskFile = VMManager.quickScanDiskFileInFolder(VmFileManager.getPath(vmID)); if (!_getDiskFile.isEmpty()) { //Error code: CR_CVBI2 if (getIntent().hasExtra("addromnow") && !addromnowdone) { @@ -984,7 +984,7 @@ public class VMCreatorActivity extends AppCompatActivity { binding.qemu.setText(Objects.requireNonNull(getIntent().getStringExtra("romextra")).replaceAll(Objects.requireNonNull(getIntent().getStringExtra("finalromfilename")), "\"" + _getDiskFile + "\"")); } else { binding.drive.setText(_getDiskFile); - binding.qemu.setText(Objects.requireNonNull(getIntent().getStringExtra("romextra")).replaceAll("OhnoIjustrealizeditsmidnightandIstillhavetodothis", AppConfig.vmFolder + vmID + "/")); + binding.qemu.setText(VmFileManager.textMarkToPath(vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra")))); } } @@ -1015,24 +1015,24 @@ public class VMCreatorActivity extends AppCompatActivity { } } } else { - if (!JSONUtils.isValidFromFile(AppConfig.vmFolder + vmID + "/rom-data.json")) { + if (!JSONUtils.isValidFromFile(VmFileManager.getConfigFile(vmID))) { DialogUtils.oneDialog(this, getResources().getString(R.string.oops), getResources().getString(R.string.error_CR_CVBI4), getResources().getString(R.string.ok), true, R.drawable.warning_48px, true, null, null); return; } try { - loadConfig(new Gson().fromJson(FileUtils.readFromFile(this, new File(AppConfig.vmFolder + vmID + "/rom-data.json")), DataMainRoms.class)); + loadConfig(new Gson().fromJson(FileUtils.readFromFile(this, new File(VmFileManager.getConfigFile(vmID))), DataMainRoms.class)); } catch (JsonSyntaxException e) { DialogUtils.oneDialog(this, getResources().getString(R.string.oops), getResources().getString(R.string.error_CR_CVBI4), getResources().getString(R.string.ok), true, R.drawable.warning_48px, true, null, null); return; } - JSONObject jObj = new JSONObject(FileUtils.readFromFile(this, new File(AppConfig.vmFolder + vmID + "/rom-data.json"))); + JSONObject jObj = new JSONObject(FileUtils.readFromFile(this, new File(VmFileManager.getConfigFile(vmID)))); if (jObj.has("vmID")) { if (!jObj.isNull("vmID")) { if (!jObj.getString("vmID").isEmpty()) { - FileUtils.move(AppConfig.vmFolder + vmID, AppConfig.vmFolder + jObj.getString("vmID")); + FileUtils.move(VmFileManager.getConfigFile(vmID), VmFileManager.getConfigFile( jObj.getString("vmID"))); vmID = jObj.getString("vmID"); } } @@ -1040,7 +1040,7 @@ public class VMCreatorActivity extends AppCompatActivity { //It can be deleted because there are few users of the old version. if (!_filename.replace(".cvbi", "").isEmpty()) - FileUtils.move(AppConfig.vmFolder + _filename.replace(".cvbi", ""), AppConfig.vmFolder + vmID); + FileUtils.move(AppConfig.vmFolder + _filename.replace(".cvbi", ""), VmFileManager.getPath(vmID)); if (!jObj.has("drive") && !jObj.has("cdrom") && !jObj.has("qemu")) { DialogUtils.oneDialog(this, getResources().getString(R.string.problem_has_been_detected), getResources().getString(R.string.this_rom_is_missing_too_much_information), R.drawable.warning_24px); @@ -1066,12 +1066,12 @@ public class VMCreatorActivity extends AppCompatActivity { Log.e(TAG, "afterExtractCVBIFile: " + e.getMessage()); } - if (FileUtils.isFileExists(AppConfig.vmFolder + vmID + "/cqcm.json")) { - FileUtils.writeToFile(AppConfig.vmFolder + vmID, "cqcm.json", FileUtils.readAFile(AppConfig.vmFolder + vmID + "/cqcm.json").replace("OhnoIjustrealizeditsmidnightandIstillhavetodothis", AppConfig.vmFolder + vmID + "/")); + if (VmFileManager.isCreateCommandConfigFileExists(vmID)) { + FileUtils.writeToFile(VmFileManager.getPath(vmID), VmFileManager.CREATE_COMMAND_CONFIG_FILE_NAME, VmFileManager.textMarkToPath(vmID, FileUtils.readAFile(VmFileManager.getCreateCommandConfigFile(vmID)))); } - if (FileUtils.isFileExists(AppConfig.vmFolder + vmID + "/snapshot.sh")) { - FileUtils.writeToFile(AppConfig.vmFolder + vmID, "snapshot.sh", FileUtils.readAFile(AppConfig.vmFolder + vmID + "/snapshot.sh").replace("OhnoIjustrealizeditsmidnightandIstillhavetodothis", AppConfig.vmFolder + vmID + "/")); + if (VmFileManager.isSnapshotShExists(vmID)) { + FileUtils.writeToFile(VmFileManager.getPath(vmID), VmFileManager.SNAPSHOT_SH_FILE_NAME, VmFileManager.textMarkToPath(vmID, FileUtils.readAFile(VmFileManager.getSnapshotSh(vmID)))); } } diff --git a/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java b/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java index b07ecdd..48dc236 100644 --- a/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java +++ b/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java @@ -28,15 +28,14 @@ import com.vectras.vm.R; import com.vectras.vm.VMManager; import com.vectras.vm.logger.VectrasStatus; import com.vectras.vm.manager.QmpSender; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.manager.VmAudioManager; import com.vectras.vm.settings.ExternalVNCSettingsActivity; -import com.vectras.vm.utils.DeviceUtils; import com.vectras.vm.utils.DialogUtils; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.NetworkUtils; import com.vectras.vm.utils.PackageUtils; import com.vectras.vm.utils.ServiceUtils; -import com.vectras.vterm.Terminal; import java.io.File; @@ -155,7 +154,7 @@ public class MainStartVM { if (VMManager.isVMRunning(context, finalvmID)) { Toast.makeText(context, "This VM is already running.", Toast.LENGTH_LONG).show(); DisplaySystem.launch(context); - VmAudioManager.stream(vmID); + if (!MainSettingsManager.getVmUi(context).equals("VNC")) VmAudioManager.stream(vmID); return; } @@ -195,7 +194,7 @@ public class MainStartVM { return; } - FileUtils.delete(AppConfig.vmFolder + vmID + "/audio.raw"); + VmFileManager.removeTemp(context, vmID); TextView vmBootNote = showProgressDialog(context, vmName, thumbnailFile, vmID); @@ -326,7 +325,7 @@ public class MainStartVM { }); } - FileUtils.writeToFile(AppConfig.vmFolder + vmID, "snapshot.sh", env); + FileUtils.writeToFile(VmFileManager.getPath(vmID), VmFileManager.SNAPSHOT_SH_FILE_NAME, env); Log.i(TAG, "Virtual machine running."); @@ -390,9 +389,9 @@ public class MainStartVM { .placeholder(R.drawable.ic_computer_180dp_with_padding) .error(R.drawable.ic_computer_180dp_with_padding) .into(ivThumbnail); - } else if (FileUtils.isFileExists(AppConfig.vmFolder + vmID + "/screenshot.png")) { + } else if (VmFileManager.isScreenshotPngExists(vmID)) { Glide.with(context.getApplicationContext()) - .load(new File(AppConfig.vmFolder + vmID + "/screenshot.png")) + .load(new File(VmFileManager.getScreenshotPng(vmID))) .placeholder(R.drawable.ic_computer_180dp_with_padding) .error(R.drawable.ic_computer_180dp_with_padding) .into(ivThumbnail); diff --git a/app/src/main/java/com/vectras/vm/main/vms/VmsHomeAdapter.java b/app/src/main/java/com/vectras/vm/main/vms/VmsHomeAdapter.java index 74fc8a1..1d144d0 100644 --- a/app/src/main/java/com/vectras/vm/main/vms/VmsHomeAdapter.java +++ b/app/src/main/java/com/vectras/vm/main/vms/VmsHomeAdapter.java @@ -22,6 +22,7 @@ import com.vectras.vm.StartVM; import com.vectras.vm.VMManager; import com.vectras.vm.main.core.MainStartVM; import com.vectras.vm.main.core.RomOptionsDialog; +import com.vectras.vm.manager.VmFileManager; import com.vectras.vm.utils.FileUtils; import java.io.File; @@ -66,9 +67,9 @@ public class VmsHomeAdapter extends RecyclerView.Adapter { + boolean isRuning; + if (Terminal.executeShellCommandWithResult("pgrep -f 'http.server 19000'", context).isEmpty()) { + if (!Terminal.executeShellCommandWithResult("which python3", context).contains("python3")) + Terminal.executeShellCommandWithResult("apk add python3", context); + + startCommand(context); + + isRuning = !Terminal.executeShellCommandWithResult("sleep 1; pgrep -f 'http.server 19000'", context).isEmpty(); + } else { + isRuning = true; + } + + new Handler(Looper.getMainLooper()).post(() -> { + progressDialog.reset(); + + if (isRuning) { + DialogUtils.threeDialog( + context, + context.getString(R.string.the_server_is_running), + String.format(context.getString(R.string.host_shared_folder_format_content), MAIN_URL, EX_UPLOAD_COMMAND), + context.getString(R.string.copy_link), + context.getString(R.string.copy_upload_command), + context.getString(R.string.close), + true, + R.drawable.folder_24px, + true, + () -> ClipboardUltils.copyToClipboard(context, MAIN_URL), + () -> ClipboardUltils.copyToClipboard(context, EX_UPLOAD_COMMAND), + null, + null + ); + } else { + DialogUtils.oopsDialog(context, context.getString(R.string.host_shared_folder_error_content)); + } + }); + }).start(); + } + + public static void startCommand(Context _context) { + Terminal vterm = new Terminal(_context); + vterm.executeShellCommand2("python3 -m http.server 19000 --directory " + SHARED_DIR, false, null); + } +} diff --git a/app/src/main/java/com/vectras/vm/manager/QmpSender.java b/app/src/main/java/com/vectras/vm/manager/QmpSender.java index da9dff3..627481d 100644 --- a/app/src/main/java/com/vectras/vm/manager/QmpSender.java +++ b/app/src/main/java/com/vectras/vm/manager/QmpSender.java @@ -16,6 +16,7 @@ import com.vectras.qemu.Config; import com.vectras.qemu.utils.QmpClient; import com.vectras.vm.AppConfig; import com.vectras.vm.R; +import com.vectras.vm.VectrasApp; import java.io.StringReader; @@ -113,11 +114,11 @@ public class QmpSender { } public static String migrate() { - return send("migrate \"exec:cat > " + AppConfig.vmFolder + Config.vmID + "/snapshot.bin\""); + return send("migrate \"exec:cat > " + VmFileManager.getSnapshotBin(Config.vmID) + "\""); } public static boolean takeScreenshot() { - return isSuccess(send("screendump " + AppConfig.vmFolder + Config.vmID + "/screenshot.ppm")); + return isSuccess(send("screendump " + VmFileManager.getScreenshotPpm(VectrasApp.getContext(), Config.vmID))); } public static String getAllDevice() { diff --git a/app/src/main/java/com/vectras/vm/manager/VmActions.java b/app/src/main/java/com/vectras/vm/manager/VmActions.java index 104696f..60a7581 100644 --- a/app/src/main/java/com/vectras/vm/manager/VmActions.java +++ b/app/src/main/java/com/vectras/vm/manager/VmActions.java @@ -4,7 +4,6 @@ import android.content.Context; import android.net.Uri; import com.vectras.qemu.Config; -import com.vectras.vm.AppConfig; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.ImageUtils; @@ -18,15 +17,15 @@ public class VmActions { if (isSaveToGallery) { Uri imageFile = ImageUtils.saveToGallery( context, - ImageUtils.ppmToBitmap(new File(AppConfig.vmFolder + Config.vmID + "/screenshot.ppm")), + ImageUtils.ppmToBitmap(new File(VmFileManager.getScreenshotPpm(context, Config.vmID))), String.valueOf(System.currentTimeMillis()) ); - FileUtils.copyFileFromUri(context, imageFile, AppConfig.vmFolder + Config.vmID + "/screenshot.png"); + FileUtils.copyFileFromUri(context, imageFile, VmFileManager.getScreenshotPng(Config.vmID)); } else { ImageUtils.saveBitmapToPNGFile( - ImageUtils.ppmToBitmap(new File(AppConfig.vmFolder + Config.vmID + "/screenshot.ppm")), - AppConfig.vmFolder + Config.vmID, + ImageUtils.ppmToBitmap(new File(VmFileManager.getScreenshotPpm(context, Config.vmID))), + VmFileManager.getPath(Config.vmID), "screenshot.png" ); } @@ -35,7 +34,7 @@ public class VmActions { } } - FileUtils.delete(AppConfig.vmFolder + Config.vmID + "/screenshot.ppm"); + VmFileManager.removeScreenshotPpm(context, Config.vmID); return isSaved; } diff --git a/app/src/main/java/com/vectras/vm/manager/VmAudioManager.java b/app/src/main/java/com/vectras/vm/manager/VmAudioManager.java index ca2aa22..058bb76 100644 --- a/app/src/main/java/com/vectras/vm/manager/VmAudioManager.java +++ b/app/src/main/java/com/vectras/vm/manager/VmAudioManager.java @@ -3,7 +3,6 @@ package com.vectras.vm.manager; import android.util.Log; import com.vectras.qemu.Config; -import com.vectras.vm.AppConfig; import com.vectras.vm.VectrasApp; import com.vectras.vm.utils.FileUtils; import com.vectras.vm.utils.StreamAudio; @@ -15,7 +14,7 @@ public class VmAudioManager { public static void stream(String vmID) { if (streamAudio.isPlaying()) streamAudio.stop(); - streamAudio.setFile(AppConfig.vmFolder + vmID + "/audio.raw"); + streamAudio.setFile(VmFileManager.getAudioRaw(VectrasApp.getContext(), vmID)); streamAudio.play(); new Thread(() -> { diff --git a/app/src/main/java/com/vectras/vm/manager/VmControllerDialog.java b/app/src/main/java/com/vectras/vm/manager/VmControllerDialog.java index e5cfab5..43145a4 100644 --- a/app/src/main/java/com/vectras/vm/manager/VmControllerDialog.java +++ b/app/src/main/java/com/vectras/vm/manager/VmControllerDialog.java @@ -64,6 +64,11 @@ public class VmControllerDialog extends DialogFragment { dismiss(); }); + binding.lnFolderSharingServer.setOnClickListener(v -> { + HostSharedFolder.start(requireActivity()); + dismiss(); + }); + if (infoBlock != null && (infoBlock.contains(QmpSender.DEFAULT_OPTICAL_DISC_1_ID) || infoBlock.contains(QmpSender.DEFAULT_OPTICAL_DISC_2_ID) || infoBlock.contains(QmpSender.DEFAULT_FLOPPY_DISK_0_ID) @@ -164,7 +169,7 @@ public class VmControllerDialog extends DialogFragment { }); - if (requireActivity() instanceof MainVNCActivity) { + if (isAdded() && requireActivity() instanceof MainVNCActivity) { binding.lnRefresh.setOnClickListener(v -> { requireActivity().startActivity(new Intent(requireActivity(), MainVNCActivity.class)); requireActivity().overridePendingTransition(0, 0); diff --git a/app/src/main/java/com/vectras/vm/manager/VmFileManager.java b/app/src/main/java/com/vectras/vm/manager/VmFileManager.java new file mode 100644 index 0000000..8902d62 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/manager/VmFileManager.java @@ -0,0 +1,159 @@ +package com.vectras.vm.manager; + +import android.content.Context; +import android.util.Log; + +import com.vectras.vm.AppConfig; +import com.vectras.vm.utils.FileUtils; + +import java.io.File; +import java.util.Objects; + +public class VmFileManager { + private static final String TAG = "VmFileManager"; + public static final String CONFIG_FILE_NAME = "rom-data.json"; + public static final String THUMBNAIL_FILE_NAME = "thumbnail.png"; + public static final String SCREENSHOT_PPM_FILE_NAME = "screenshot.ppm"; + public static final String SCREENSHOT_PNG_FILE_NAME = "screenshot.png"; + public static final String AUDIO_STREAM_FILE_NAME = "audio.raw"; + public static final String SNAPSHOT_SH_FILE_NAME = "snapshot.sh"; + public static final String SNAPSHOT_BIN_FILE_NAME = "snapshot.bin"; + public static final String CREATE_COMMAND_CONFIG_FILE_NAME = "cqcm.json"; + public static final String TEXT_MARK_VM_PATH = "OhnoIjustrealizeditsmidnightandIstillhavetodothis"; + public static final String HIDE_VM_SUFFIX = "_"; + + + public static boolean hide(String vmId) { + return FileUtils.rename(getPath(vmId), HIDE_VM_SUFFIX + vmId); + } + + public static String replaceToHide(String vmId, String content) { + return content.replace(quickGetPath(vmId), quickGetPathHide(vmId)); + } + + public static String replaceToShow(String vmId, String content) { + String finalVmId = vmId; + if (finalVmId.startsWith(HIDE_VM_SUFFIX)) + finalVmId = vmId.substring(1); + + return content.replace(quickGetPathHide(finalVmId), quickGetPath(finalVmId)); + } + + public static boolean visible(String vmId) { + return FileUtils.rename(getPath(HIDE_VM_SUFFIX + vmId), vmId); + } + + public static String getPath(String vmId, String childFilePath) { + return new File(getPath(vmId), childFilePath).getAbsolutePath(); + } + + public static String getPath(String vmId) { + String path = new File(AppConfig.vmFolder, vmId).getAbsolutePath(); + FileUtils.createDirectory(path); + return path + "/"; + } + + public static String getPathHide(String vmId) { + String path = new File(AppConfig.vmFolder, HIDE_VM_SUFFIX + vmId).getAbsolutePath(); + return path + "/"; + } + + public static String quickGetPath(String vmId) { + return new File(AppConfig.vmFolder, vmId).getAbsolutePath(); + } + + public static String quickGetPathHide(String vmId) { + return new File(AppConfig.vmFolder, HIDE_VM_SUFFIX + vmId).getAbsolutePath(); + } + + public static boolean delete(String vmId) { + return FileUtils.delete(getPath(vmId)); + } + + public static String getTempPath(Context context, String vmId, String childFilePath) { + return new File(getTempPath(context, vmId), childFilePath).getAbsolutePath(); + } + + public static String getTempPath(Context context, String vmId) { + String path = new File(Objects.requireNonNull(context.getExternalCacheDir()).getAbsolutePath(), "temp/" + vmId).getAbsolutePath(); + FileUtils.createDirectory(path); + return path + "/"; + } + + public static boolean removeTemp(Context context, String vmId, String childFilePath) { + return FileUtils.delete(new File(getTempPath(context, vmId, childFilePath))); + } + + public static boolean removeTemp(Context context, String vmId) { + return FileUtils.delete(getTempPath(context, vmId)); + } + + public static boolean isConfigFileExists(String vmId) { + return FileUtils.isFileExists(getConfigFile(vmId)); + } + + public static String getConfigFile(String vmId) { + Log.d(TAG, VmFileManager.getPath(vmId, CONFIG_FILE_NAME)); + return VmFileManager.getPath(vmId, CONFIG_FILE_NAME); + } + + public static String getThumbnail(String vmId) { + return VmFileManager.getPath(vmId, THUMBNAIL_FILE_NAME); + } + + public static String getScreenshotPpm(Context context, String vmId) { + return VmFileManager.getTempPath(context, vmId, SCREENSHOT_PPM_FILE_NAME); + } + + public static boolean removeScreenshotPpm(Context context, String vmId) { + return VmFileManager.removeTemp(context, vmId, SCREENSHOT_PPM_FILE_NAME); + } + + public static boolean isScreenshotPngExists(String vmId) { + return FileUtils.isFileExists(getScreenshotPng(vmId)); + } + + public static String getScreenshotPng(String vmId) { + return VmFileManager.getPath(vmId, SCREENSHOT_PNG_FILE_NAME); + } + + public static String getAudioRaw(Context context, String vmId) { + return VmFileManager.getTempPath(context, vmId, AUDIO_STREAM_FILE_NAME); + } + + public static boolean removeAudioRaw(Context context, String vmId) { + return VmFileManager.removeTemp(context, vmId, AUDIO_STREAM_FILE_NAME); + } + + public static boolean isSnapshotShExists(String vmId) { + return FileUtils.isFileExists(getSnapshotSh(vmId)); + } + + public static String getSnapshotSh(String vmId) { + return VmFileManager.getPath(vmId, SNAPSHOT_SH_FILE_NAME); + } + + public static boolean isSnapshotBinExists(String vmId) { + return FileUtils.isFileExists(getSnapshotBin(vmId)); + } + + public static String getSnapshotBin(String vmId) { + return VmFileManager.getPath(vmId, SNAPSHOT_BIN_FILE_NAME); + } + + public static boolean isCreateCommandConfigFileExists(String vmId) { + return FileUtils.isFileExists(getCreateCommandConfigFile(vmId)); + } + + public static String getCreateCommandConfigFile(String vmId) { + return VmFileManager.getPath(vmId, CREATE_COMMAND_CONFIG_FILE_NAME); + } + + public static String textMarkToPath(String vmId, String content) { + return content.replace(TEXT_MARK_VM_PATH, getPath(vmId)); + } + + public static String pathToTextMark(String vmId, String content) { + return content.replace(getPath(vmId), TEXT_MARK_VM_PATH); + } +} diff --git a/app/src/main/java/com/vectras/vm/setupwizard/SetupFeatureCore.java b/app/src/main/java/com/vectras/vm/setupwizard/SetupFeatureCore.java index 988aa35..2446899 100644 --- a/app/src/main/java/com/vectras/vm/setupwizard/SetupFeatureCore.java +++ b/app/src/main/java/com/vectras/vm/setupwizard/SetupFeatureCore.java @@ -3,6 +3,7 @@ package com.vectras.vm.setupwizard; import android.app.Activity; import android.content.Context; import android.os.Build; +import android.os.Environment; import android.util.Log; import com.vectras.vm.R; 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 41b5664..902785f 100644 --- a/app/src/main/java/com/vectras/vm/utils/FileUtils.java +++ b/app/src/main/java/com/vectras/vm/utils/FileUtils.java @@ -71,8 +71,20 @@ public class FileUtils { @SuppressLint("NewApi") public static String getPath(Context context, final Uri uri) { - if ((uri.toString().startsWith("content://ru.zdevs.zarchiver") || uri.toString().startsWith("content://bin.mt.plus")) && uri.getPath() != null && isFileExists(uri.getPath())) - return uri.getPath(); + if ((uri.toString().startsWith("content://ru.zdevs.zarchiver") || + uri.toString().startsWith("content://bin.mt.plus") || + uri.toString().startsWith("content://com.android.fileexplorer.myprovider") || + uri.toString().startsWith("content://com.estrongs.files")) && + uri.getPath() != null && + isFileExists(uri.getPath())) { + String path = uri.getPath(); + + if (uri.toString().startsWith("content://com.android.fileexplorer.myprovider/external_files")) { + path = new File(Environment.getExternalStorageDirectory(), path.substring("/external_files".length())).getAbsolutePath(); + } + + return path; + } // check here to KITKAT or new version final boolean isKitKat = true; diff --git a/app/src/main/java/com/vectras/vm/utils/StreamAudio.java b/app/src/main/java/com/vectras/vm/utils/StreamAudio.java index 5849589..48410cf 100644 --- a/app/src/main/java/com/vectras/vm/utils/StreamAudio.java +++ b/app/src/main/java/com/vectras/vm/utils/StreamAudio.java @@ -14,6 +14,7 @@ public class StreamAudio { private Context context; private boolean isPlay; private String filePath = ""; + private int sampleRate = 48000; public StreamAudio(Context context) { this.context = context; @@ -35,7 +36,18 @@ public class StreamAudio { filePath = path; } + public void setMinimumSampleRate() { + sampleRate = 44100; + } + + public void setHighSampleRate() { + sampleRate = 48000; + } + + public void streamFromFile() { + if (isPlay) return; + isPlay = true; new Thread(() -> { @@ -55,7 +67,7 @@ public class StreamAudio { Log.d(TAG, "Preparing to play: " + filePath); - int minBuf = AudioTrack.getMinBufferSize(44100, + int minBuf = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); @@ -64,7 +76,7 @@ public class StreamAudio { .setUsage(AudioAttributes.USAGE_MEDIA) .build()) .setAudioFormat(new AudioFormat.Builder() - .setSampleRate(44100) + .setSampleRate(sampleRate) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .build()) diff --git a/app/src/main/java/com/vectras/vterm/Terminal.java b/app/src/main/java/com/vectras/vterm/Terminal.java index 8390770..2ec3675 100644 --- a/app/src/main/java/com/vectras/vterm/Terminal.java +++ b/app/src/main/java/com/vectras/vterm/Terminal.java @@ -194,7 +194,7 @@ public class Terminal { new Handler(Looper.getMainLooper()).post(() -> { AppConfig.temporaryLastedTerminalOutput = output.toString(); // If showResultDialog is enabled, show the dialog with the result or errors - if (showResultDialog) { + if (showResultDialog && dialogActivity != null) { String finalOutput = output.toString(); String finalErrors = errors.toString(); // bcuz there is dumb users bruh @@ -208,7 +208,6 @@ public class Terminal { public static String executeShellCommandWithResult(String userCommand, Context context) { StringBuilder output = new StringBuilder(); StringBuilder errors = new StringBuilder(); - Log.d(TAG, userCommand); VectrasStatus.logError("VTERM: >" + userCommand + ""); try { @@ -253,6 +252,8 @@ public class Terminal { output.append(e.getMessage()); errors.append(Log.getStackTraceString(e)); } + + Log.d(TAG, "executeShellCommandWithResult: " + userCommand + "\n" + output); return output.toString(); } diff --git a/app/src/main/res/layout/dialog_change_removable_devices.xml b/app/src/main/res/layout/dialog_change_removable_devices.xml index cc6dd20..3c77c45 100644 --- a/app/src/main/res/layout/dialog_change_removable_devices.xml +++ b/app/src/main/res/layout/dialog_change_removable_devices.xml @@ -87,6 +87,26 @@ android:textColor="?attr/colorControlNormal" android:text="@string/pause"/> + + + + + Không thể chụp màn hình. Đã lưu vào bộ sưu tập. Đang chụp màn hình… + Máy ảo này đang chạy. + Máy chủ đã chạy + Hãy truy cập vào liên kết này ở máy ảo để truy cập vào thư mục Download trên thiết bị của bạn:\n\n%s\n\nBạn cũng có thể gửi tệp từ trong máy ảo ra thư mục Download trên thiết bị của bạn, dưới đây là ví dụ về cách làm với curl:\n\n%s + Đã xảy ra lỗi khi khởi động máy chủ. Hãy thử lại sau. + Sao chép liên kết + Sao chép lệnh tải lên + Máy chủ chia sẻ thư mục diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c8f8050..9de23b5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -550,6 +550,13 @@ Unable to take a screenshot. Saved to the gallery. Taking a screenshot… + This VM is already running. + The server is running + Access this link on the virtual machine to access the Download folder on your device:\n\n%s\n\nYou can also send files from the virtual machine to the Download folder on your device, here\'s an example using curl:\n\n%s + An error occurred while starting the server. Please try again later. + Copy link + Copy upload command + Folder sharing server diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1dcc574..ef20a54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] activityKtx = "1.13.0" -agp = "9.1.1" +agp = "9.2.0" annotation = "1.10.0" appcompat = "1.7.1" comGoogleFirebase = "firebase-crashlytics" diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index c3c7478..1a33b60 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.9.0

\nBugs fixed.", "cancellable": true, - "versionCodeBeta":"102", - "versionNameBeta":"3.9.8", - "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,3.6.8,3.6.9,3.7.1,3.7.2,3.7.3,3.7.4,3.7.5,3.7.6,3.7.7,3.7.8,3.7.9,3.8.0,3.8.1,3.8.2,3.8.3,3.8.4,3.8.5,3.8.6,3.8.7,3.8.8,3.8.9,3.9.0,3.9.1,3.9.2,3.9.3,3.9.4,3.9.5,3.9.6,3.9.7,3.9.8", + "versionCodeBeta":"103", + "versionNameBeta":"3.9.9", + "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,3.6.8,3.6.9,3.7.1,3.7.2,3.7.3,3.7.4,3.7.5,3.7.6,3.7.7,3.7.8,3.7.9,3.8.0,3.8.1,3.8.2,3.8.3,3.8.4,3.8.5,3.8.6,3.8.7,3.8.8,3.8.9,3.9.0,3.9.1,3.9.2,3.9.3,3.9.4,3.9.5,3.9.6,3.9.7,3.9.8,3.9.9", "sizeBeta": "45 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

3.9.8

Bugs fixed.", + "MessageBeta": "

3.9.9

Bugs fixed.", "cancellableBeta": true }