Merge pull request #519 from AnBui2004/master

3.6.7
This commit is contained in:
An Bui 2026-01-10 21:13:22 +07:00 committed by GitHub
commit ff77f89609
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 1333 additions and 1249 deletions

View file

@ -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

View file

@ -130,7 +130,7 @@
android:exported="true"
android:hardwareAccelerated="true" />
<activity
android:name=".QemuParamsEditorActivity"
android:name=".creator.QemuParamsEditorActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:exported="false"
android:hardwareAccelerated="true"
@ -174,7 +174,7 @@
android:exported="true"
android:label="Data Explorer" />
<activity
android:name=".SetArchActivity"
android:name=".creator.SetArchActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:label="Set Qemu Version" />

View file

@ -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<String, Object> mapForGetData = new HashMap<>();
public static ArrayList<HashMap<String, Object>> listmapForGetData = new ArrayList<>();
private SharedPreferences data;
public String getRomPath = "";
public String iconfile = "";
public String diskfile = "";
public String cdromfile = "";
private boolean isExporting = false;
private ActivityResultLauncher<String> 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<String, Object> vmConfigMap = new HashMap<>();
listmapForGetData = new Gson().fromJson(FileUtils.readAFile(AppConfig.romsdatajson), new TypeToken<ArrayList<HashMap<String, Object>>>() {
}.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<String> _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();
}
},

View file

@ -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;
}
}
}

View file

@ -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() {

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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<HashMap<String, Object>> 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,

View file

@ -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);

View file

@ -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();
});

View file

@ -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<String, String> 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;

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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;
}
}
}

View file

@ -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));

View file

@ -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<GithubUser> call = service.getUser(username);
call.enqueue(new Callback<GithubUser>() {
@Override
public void onResponse(Call<GithubUser> call, Response<GithubUser> response) {
public void onResponse(@NonNull Call<GithubUser> call, @NonNull Response<GithubUser> 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<GithubUser> call, Throwable t) {
public void onFailure(@NonNull Call<GithubUser> 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);
}
}

View file

@ -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<StringBuilder> output = new AtomicReference<>(new StringBuilder());
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
// 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<StringBuilder> output = new AtomicReference<>(new StringBuilder());
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
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("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
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<StringBuilder> output = new AtomicReference<>(new StringBuilder());
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + userCommand + "</font>");
// 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("<font color='#4db6ac'>VTERM: >" + line + "</font>");
VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
}
while ((line = errorReader.readLine()) != null) {
Log.w(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='red'>VTERM ERROR: >" + line + "</font>");
VectrasStatus.logError("<font color='red'>VTERM ERROR: >" + line + "</font>");
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();

View file

@ -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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:background="?attr/colorSurfaceContainer"
android:animateLayoutChanges="true">
<TextView
style="@style/MaterialAlertDialog.Material3Expressive.Title.Text"
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/options"/>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/dv_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
tools:visibility="visible"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scrollbars="vertical"
android:fadeScrollbars="false"/>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/dv_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
tools:visibility="visible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|right"
android:padding="16dp">
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:id="@+id/btn_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/close"/>
</LinearLayout>
</LinearLayout>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -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">
<TextView
android:id="@+id/textview"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingRight="16dp"
android:text="TextView" />
<ImageView
android:id="@+id/iv_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/check_24px"/>
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:text="TextView" />
</LinearLayout>

View file

@ -508,6 +508,8 @@
<string name="hard_disk">Hard disk</string>
<string name="floppy_disk">Floppy disk</string>
<string name="network">Network</string>
<string name="rom_successfully_exported">Rom successfully exported.</string>
<string name="options">Options</string>
<!--======================TERMUX STRINGS====================-->

View file

@ -5,11 +5,11 @@
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
"Message": "<h2>3.6.0</h2>\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": "<h2>3.6.6</h2>Bugs fixed.",
"MessageBeta": "<h2>3.6.7</h2>Bugs fixed.",
"cancellableBeta": true
}