mirror of
https://github.com/xoureldeen/Vectras-VM-Android.git
synced 2026-05-19 16:42:13 +00:00
commit
81995d45df
26 changed files with 642 additions and 69 deletions
|
|
@ -12,8 +12,8 @@ android {
|
|||
applicationId "com.vectras.vm"
|
||||
minSdk minApi
|
||||
targetSdk targetApi
|
||||
versionCode 95
|
||||
versionName "3.9.1"
|
||||
versionCode 96
|
||||
versionName "3.9.2"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
||||
|
|
|
|||
BIN
app/src/main/assets/roms/3dfx-wrappers.iso
Normal file
BIN
app/src/main/assets/roms/3dfx-wrappers.iso
Normal file
Binary file not shown.
|
|
@ -6,12 +6,17 @@ import retrofit2.Call;
|
|||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Streaming;
|
||||
import retrofit2.http.Url;
|
||||
|
||||
public interface ApiService {
|
||||
@GET
|
||||
Call<ResponseBody> getRawJson(@Url String url);
|
||||
|
||||
@Streaming
|
||||
@GET
|
||||
Call<ResponseBody> downloadFile(@Url String url);
|
||||
|
||||
@POST
|
||||
Call<ResponseBody> post(@Url String url, @Body RequestBody body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.anbui.elephant.retrofit2utils;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
|
@ -85,4 +88,58 @@ public class Retrofit2Utils {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface DownloadCallback {
|
||||
void onProgress(int percent);
|
||||
void onResult(boolean success, String path, Throwable error);
|
||||
}
|
||||
|
||||
public static void download(String url, String outputPath, DownloadCallback callback) {
|
||||
api.downloadFile(url).enqueue(new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
|
||||
if (!response.isSuccessful() || response.body() == null) {
|
||||
callback.onResult(false, null, new Exception("Response error"));
|
||||
return;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
try (InputStream in = response.body().byteStream();
|
||||
OutputStream out = new FileOutputStream(outputPath)) {
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
long total = response.body().contentLength();
|
||||
long downloaded = 0;
|
||||
|
||||
int read;
|
||||
int lastPercent = 0;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
downloaded += read;
|
||||
|
||||
if (total > 0) {
|
||||
int percent = (int) (downloaded * 100 / total);
|
||||
if (percent != lastPercent) {
|
||||
lastPercent = percent;
|
||||
callback.onProgress(percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.flush();
|
||||
callback.onResult(true, outputPath, null);
|
||||
|
||||
} catch (Exception e) {
|
||||
callback.onResult(false, null, e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||
callback.onResult(false, null, t);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,4 +117,7 @@ public class AppConfig {
|
|||
|
||||
public static String patreonLink = "https://www.patreon.com/VectrasTeam";
|
||||
|
||||
public static String virtIOWinUrl = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.285-1/virtio-win.iso";
|
||||
public static String virtIOWinUrlMd5 = "9e650d0e7c6e017a91ca299c8f7ed766";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ public class ExportRomActivity extends AppCompatActivity {
|
|||
|
||||
vmConfigMap.put("bootFrom", current.bootFrom);
|
||||
vmConfigMap.put("isShowBootMenu", current.isShowBootMenu);
|
||||
vmConfigMap.put("isUseUefi", current.isUseUefi);
|
||||
vmConfigMap.put("qemu", current.itemExtra.replace(getRomPath, "OhnoIjustrealizeditsmidnightandIstillhavetodothis"));
|
||||
vmConfigMap.put("arch", current.itemArch);
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class SplashActivity extends AppCompatActivity {
|
|||
Log.e(TAG, "Create roms-data.json file failed: ", e);
|
||||
}
|
||||
|
||||
FileInstaller.installFiles(this, true);
|
||||
//FileInstaller.installFiles(this, true);
|
||||
}
|
||||
|
||||
private void setupFolders() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ 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.setupwizard.SetupFeatureCore;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.TextUtils;
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ public class StartVM {
|
|||
public static String cache;
|
||||
|
||||
public static String cdrompath;
|
||||
private static boolean isUseUefi;
|
||||
|
||||
public static String env(Activity activity, DataMainRoms vmData) {
|
||||
if (VMManager.isNeedLoadMigrate() && FileUtils.isFileExists(AppConfig.vmFolder + Config.vmID + "/snapshot.sh")) {
|
||||
|
|
@ -49,6 +51,7 @@ public class StartVM {
|
|||
|
||||
extraParams = bootParams + extraParams;
|
||||
cdrompath = vmData.imgCdrom;
|
||||
isUseUefi = vmData.isUseUefi;
|
||||
return env(activity, extraParams, vmData.itemPath, false);
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +215,7 @@ public class StartVM {
|
|||
bios += "file=" + AppConfig.basefiledir + "QEMU_EFI.img,format=raw,readonly=on,if=pflash";
|
||||
bios += " -drive ";
|
||||
bios += "file=" + AppConfig.basefiledir + "QEMU_VARS.img,format=raw,if=pflash";
|
||||
} else if (MainSettingsManager.getArch(activity).equals("X86_64") && MainSettingsManager.getuseUEFI(activity)) {
|
||||
} else if (MainSettingsManager.getArch(activity).equals("X86_64") && (MainSettingsManager.getuseUEFI(activity) || isUseUefi)) {
|
||||
bios = "-drive ";
|
||||
bios += "file=" + AppConfig.basefiledir + "RELEASEX64_OVMF.fd,format=raw,readonly=on,if=pflash";
|
||||
bios += " -drive ";
|
||||
|
|
@ -221,6 +224,8 @@ public class StartVM {
|
|||
bios = "-bios ";
|
||||
bios += AppConfig.basefiledir + "bios-vectras.bin";
|
||||
}
|
||||
|
||||
extractFirmware(activity);
|
||||
}
|
||||
|
||||
String machine = "-M ";
|
||||
|
|
@ -279,6 +284,8 @@ public class StartVM {
|
|||
params.add("defer");
|
||||
}
|
||||
|
||||
isUseUefi = false;
|
||||
|
||||
return String.join(" ", params);
|
||||
}
|
||||
|
||||
|
|
@ -355,4 +362,28 @@ public class StartVM {
|
|||
.trim();
|
||||
}
|
||||
|
||||
public static void extractFirmware(Context context) {
|
||||
if (MainSettingsManager.useDefaultBios(context)) {
|
||||
String arch = MainSettingsManager.getArch(context);
|
||||
|
||||
FileUtils.createDirectory(AppConfig.basefiledir);
|
||||
|
||||
if (arch.equals("ARM64")) {
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "QEMU_EFI.img"))
|
||||
SetupFeatureCore.copyAssetToFile(context, "roms/QEMU_EFI.img", AppConfig.basefiledir + "QEMU_EFI.img");
|
||||
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "QEMU_VARS.img"))
|
||||
SetupFeatureCore.copyAssetToFile(context, "roms/QEMU_VARS.img", AppConfig.basefiledir + "QEMU_VARS.img");
|
||||
} else if (arch.equals("X86_64") && (MainSettingsManager.getuseUEFI(context) || isUseUefi)) {
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "RELEASEX64_OVMF.fd"))
|
||||
SetupFeatureCore.copyAssetToFile(context, "roms/RELEASEX64_OVMF.fd", AppConfig.basefiledir + "RELEASEX64_OVMF.fd");
|
||||
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "RELEASEX64_OVMF_VARS.fd"))
|
||||
SetupFeatureCore.copyAssetToFile(context, "roms/RELEASEX64_OVMF_VARS.fd", AppConfig.basefiledir + "RELEASEX64_OVMF_VARS.fd");
|
||||
} else {
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "bios-vectras.bin"))
|
||||
SetupFeatureCore.copyAssetToFile(context, "roms/bios-vectras.bin", AppConfig.basefiledir + "bios-vectras.bin");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ 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;
|
||||
|
|
@ -25,7 +26,10 @@ import android.widget.Toast;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
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;
|
||||
|
|
@ -45,9 +49,11 @@ import com.vectras.vm.main.core.MainStartVM;
|
|||
import com.vectras.vm.main.vms.DataMainRoms;
|
||||
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;
|
||||
|
|
@ -227,6 +233,7 @@ public class VMManager {
|
|||
public static boolean hideVM(String vmId) {
|
||||
return FileUtils.rename(AppConfig.vmFolder + vmId, "_" + vmId);
|
||||
}
|
||||
|
||||
public static boolean unHideVM(String vmPath) {
|
||||
return FileUtils.rename(vmPath, new File(vmPath).getName().replace("_", ""));
|
||||
}
|
||||
|
|
@ -305,7 +312,8 @@ public class VMManager {
|
|||
_activity.runOnUiThread(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
progressDialog.reset();
|
||||
MainActivity.refeshVMListNow();
|
||||
if (!result) DialogUtils.oopsDialog(_activity, _activity.getString(R.string.an_error_occurred_while_deleting_the_vm));
|
||||
if (!result)
|
||||
DialogUtils.oopsDialog(_activity, _activity.getString(R.string.an_error_occurred_while_deleting_the_vm));
|
||||
}, 500));
|
||||
}).start();
|
||||
},
|
||||
|
|
@ -336,7 +344,8 @@ public class VMManager {
|
|||
if (isVmFilesInUse(vmId, vmList)) {
|
||||
isKeptSomeFiles = true;
|
||||
isCompleted = hideVM(vmId);
|
||||
if (isCompleted) vmList = vmList.replace(AppConfig.vmFolder + vmId, AppConfig.vmFolder + "_" + vmId);
|
||||
if (isCompleted)
|
||||
vmList = vmList.replace(AppConfig.vmFolder + vmId, AppConfig.vmFolder + "_" + vmId);
|
||||
} else {
|
||||
isCompleted = FileUtils.delete(new File(AppConfig.vmFolder + vmId));
|
||||
}
|
||||
|
|
@ -893,6 +902,11 @@ public class VMManager {
|
|||
|
||||
public static void showChangeRemovableDevicesDialog(Activity _activity, VncCanvasActivity vncCanvasActivity) {
|
||||
new Thread(() -> {
|
||||
if (FileUtils.isFileExists(AppConfig.vmFolder + Config.vmID + "/snapshot.sh")) {
|
||||
String snapshotParams = FileUtils.readAFile(AppConfig.vmFolder + Config.vmID + "/snapshot.sh");
|
||||
if (!snapshotParams.isEmpty()) lastQemuCommand = snapshotParams;
|
||||
}
|
||||
|
||||
String allDevice = getAllDevicesInQemu();
|
||||
|
||||
_activity.runOnUiThread(() -> {
|
||||
|
|
@ -901,7 +915,7 @@ public class VMManager {
|
|||
.setView(_view)
|
||||
.create();
|
||||
|
||||
_view.findViewById(R.id.ln_pause).setOnClickListener( v -> {
|
||||
_view.findViewById(R.id.ln_pause).setOnClickListener(v -> {
|
||||
DialogUtils.twoDialog(
|
||||
_activity,
|
||||
_activity.getString(R.string.pause),
|
||||
|
|
@ -978,8 +992,31 @@ public class VMManager {
|
|||
ejectCDROM(_activity);
|
||||
_dialog.dismiss();
|
||||
});
|
||||
|
||||
if (!allDevice.contains(AppConfig.basefiledir + "3dfx-wrappers.iso")) _view.findViewById(R.id.iv_eject3dfx).setVisibility(View.GONE);
|
||||
|
||||
_view.findViewById(R.id.ln_3dfx).setOnClickListener(v -> {
|
||||
if (allDevice.contains(AppConfig.basefiledir + "3dfx-wrappers.iso")) {
|
||||
ejectCDROM(_activity);
|
||||
} else {
|
||||
mount3dfxWrappersTool(_activity);
|
||||
}
|
||||
_dialog.dismiss();
|
||||
});
|
||||
|
||||
if (!allDevice.contains(AppConfig.basefiledir + "virtio-win.iso")) _view.findViewById(R.id.iv_ejectvirtio).setVisibility(View.GONE);
|
||||
|
||||
_view.findViewById(R.id.ln_virtio).setOnClickListener(v -> {
|
||||
if (allDevice.contains(AppConfig.basefiledir + "virtio-win.iso")) {
|
||||
ejectCDROM(_activity);
|
||||
} else {
|
||||
mountVirtIOWinTool(_activity);
|
||||
}
|
||||
_dialog.dismiss();
|
||||
});
|
||||
} else {
|
||||
_view.findViewById(R.id.ln_cdrom).setVisibility(View.GONE);
|
||||
_view.findViewById(R.id.ln_tools).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (allDevice.contains("floppy0")) {
|
||||
|
|
@ -1163,6 +1200,116 @@ public class VMManager {
|
|||
}, 200);
|
||||
}
|
||||
|
||||
public static void mount3dfxWrappersTool(Activity activity) {
|
||||
new Thread(() -> {
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "3dfx-wrappers.iso"))
|
||||
SetupFeatureCore.copyAssetToFile(activity, "roms/3dfx-wrappers.iso", AppConfig.basefiledir + "3dfx-wrappers.iso");
|
||||
|
||||
activity.runOnUiThread(() -> changeCDROM(AppConfig.basefiledir + "3dfx-wrappers.iso", activity));
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void mountVirtIOWinTool(Activity activity) {
|
||||
new Thread(() -> {
|
||||
if (!FileUtils.isFileExists(AppConfig.basefiledir + "virtio-win.iso")) {
|
||||
FileUtils.delete(new File(AppConfig.basefiledir + "virtio-win.bin"));
|
||||
activity.runOnUiThread(() -> DialogUtils.twoDialog(
|
||||
activity,
|
||||
activity.getString(R.string.download_required),
|
||||
activity.getString(R.string.this_tool_needs_to_be_downloaded_before_use),
|
||||
activity.getString(R.string.ok),
|
||||
activity.getString(R.string.cancel),
|
||||
true,
|
||||
R.drawable.arrow_downward_24px,
|
||||
true,
|
||||
() -> new Thread(() -> {
|
||||
|
||||
int notificationId = 30;
|
||||
|
||||
if (!NotificationUtils.isChannelExist(NotificationUtils.downloadChannelId, activity)) {
|
||||
NotificationUtils.createChannel("Download", "View the file download process.",
|
||||
NotificationUtils.downloadChannelId, NotificationManager.IMPORTANCE_DEFAULT, activity);
|
||||
}
|
||||
|
||||
NotificationManagerCompat manager = NotificationManagerCompat.from(VectrasApp.getContext());
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(VectrasApp.getContext(), NotificationUtils.downloadChannelId)
|
||||
.setSmallIcon(R.drawable.arrow_cool_down_24px)
|
||||
.setContentTitle(activity.getString(R.string.virtio_tools_for_windows))
|
||||
.setContentText("0%")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setOngoing(true)
|
||||
.setOnlyAlertOnce(true);
|
||||
|
||||
builder.setProgress(100, 0, false);
|
||||
manager.notify(notificationId, builder.build());
|
||||
|
||||
Retrofit2Utils.download(AppConfig.virtIOWinUrl, AppConfig.basefiledir + "virtio-win.bin", new Retrofit2Utils.DownloadCallback() {
|
||||
@Override
|
||||
public void onProgress(int percent) {
|
||||
builder.setProgress(100, percent, false)
|
||||
.setContentText(percent + "%");
|
||||
manager.notify(notificationId, builder.build());
|
||||
Log.d("DL", percent + "%");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(boolean success, String path, Throwable error) {
|
||||
if (success) {
|
||||
FileUtils.move(AppConfig.basefiledir + "virtio-win.bin", AppConfig.basefiledir + "virtio-win.iso");
|
||||
|
||||
if (DialogUtils.isAllowShow(activity)) {
|
||||
NotificationUtils.recall(activity, notificationId);
|
||||
|
||||
activity.runOnUiThread(() -> DialogUtils.twoDialog(
|
||||
activity,
|
||||
activity.getString(R.string.virtio_tools_for_windows_is_now_ready_to_use),
|
||||
activity.getString(R.string.do_you_want_to_insert_it_into_the_optical_drive_right_now),
|
||||
activity.getString(R.string.ok),
|
||||
activity.getString(R.string.cancel),
|
||||
true,
|
||||
R.drawable.check_24px,
|
||||
true,
|
||||
() -> changeCDROM(AppConfig.basefiledir + "virtio-win.iso", activity),
|
||||
null,
|
||||
null)
|
||||
);
|
||||
} else {
|
||||
Context context = VectrasApp.getContext();
|
||||
|
||||
builder.setProgress(0, 0, false)
|
||||
.setSmallIcon(R.drawable.check_24px)
|
||||
.setContentText(context.getString(R.string.virtio_tools_for_windows_is_now_ready_to_use))
|
||||
.setOngoing(false);
|
||||
|
||||
manager.notify(notificationId, builder.build());
|
||||
}
|
||||
} else {
|
||||
FileUtils.delete(new File(AppConfig.basefiledir + "virtio-win.bin"));
|
||||
|
||||
if (DialogUtils.isAllowShow(activity)) {
|
||||
activity.runOnUiThread(() -> DialogUtils.oopsDialog(activity, activity.getString(R.string.download_failed_note)));
|
||||
} else {
|
||||
Context context = VectrasApp.getContext();
|
||||
|
||||
builder.setProgress(0, 0, false)
|
||||
.setSmallIcon(R.drawable.error_96px)
|
||||
.setContentText(context.getString(R.string.download_failed_note))
|
||||
.setOngoing(false);
|
||||
|
||||
manager.notify(notificationId, builder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}).start(),
|
||||
null,
|
||||
null));
|
||||
} else {
|
||||
changeCDROM(AppConfig.basefiledir + "virtio-win.iso", activity);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void changeCDROM(String _path, Activity _activity) {
|
||||
new Thread(() -> {
|
||||
if (isUsingQ35(lastQemuCommand)) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.vectras.qemu.MainSettingsManager;
|
||||
import com.vectras.vm.AppConfig;
|
||||
import com.vectras.vm.Fragment.CreateImageDialogFragment;
|
||||
|
|
@ -73,6 +74,7 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
private String thumbnailPath = "";
|
||||
private String vmID = VMManager.idGenerator();
|
||||
private boolean isShowBootMenu = false;
|
||||
private boolean isUseUefi = false;
|
||||
private int bootFrom = 0;
|
||||
|
||||
@Override
|
||||
|
|
@ -238,12 +240,14 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
|
||||
binding.lineardisclaimer.setOnClickListener(v -> DialogUtils.oneDialog(this, getResources().getString(R.string.dont_miss_out), getResources().getString(R.string.disclaimer_when_using_rom), getResources().getString(R.string.i_agree), true, R.drawable.verified_user_24px, true, null, null));
|
||||
|
||||
binding.lnShowbootmenu.setOnClickListener(v -> binding.cbShowbootmenu.toggle());
|
||||
binding.cbShowbootmenu.setOnCheckedChangeListener((button, isChecked) -> isShowBootMenu = isChecked);
|
||||
binding.cbvShowbootmenu.setOnCheckedChangeListener((v, isChecked) -> isShowBootMenu = isChecked);
|
||||
|
||||
binding.lnBootfrom.setOnClickListener(v -> VMCreatorSelector.bootFrom(this, bootFrom, ((position, name, value) -> {
|
||||
binding.cbvUseuefi.setOnCheckedChangeListener((v, isChecked) -> isUseUefi = isChecked);
|
||||
if (!MainSettingsManager.getArch(this).equals("X86_64")) binding.cbvUseuefi.setVisibility(View.GONE);
|
||||
|
||||
binding.sbvBootfrom.setOnClickListener(v -> VMCreatorSelector.bootFrom(this, bootFrom, ((position, name, value) -> {
|
||||
bootFrom = position;
|
||||
binding.tvBootfrom.setText(name);
|
||||
binding.sbvBootfrom.setSubtitle(name);
|
||||
})));
|
||||
|
||||
modify = getIntent().getBooleanExtra("MODIFY", false);
|
||||
|
|
@ -564,9 +568,16 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
bootFrom = current.bootFrom;
|
||||
binding.tvBootfrom.setText(Objects.requireNonNull(VMCreatorSelector.getBootFrom(this, current.bootFrom).get("name")).toString());
|
||||
binding.sbvBootfrom.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getBootFrom(this, current.bootFrom).get("name")).toString());
|
||||
isShowBootMenu = current.isShowBootMenu;
|
||||
binding.cbShowbootmenu.setChecked(isShowBootMenu);
|
||||
binding.cbvShowbootmenu.setChecked(isShowBootMenu);
|
||||
|
||||
if (MainSettingsManager.getArch(this).equals("X86_64")) {
|
||||
isUseUefi = current.isUseUefi;
|
||||
binding.cbvUseuefi.setChecked(isUseUefi);
|
||||
} else {
|
||||
binding.cbvUseuefi.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -698,6 +709,7 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
vmConfigMap.put("imgArch", MainSettingsManager.getArch(this));
|
||||
vmConfigMap.put("bootFrom", bootFrom);
|
||||
vmConfigMap.put("isShowBootMenu", isShowBootMenu);
|
||||
vmConfigMap.put("isUseUefi", isUseUefi);
|
||||
vmConfigMap.put("vmID", vmID);
|
||||
vmConfigMap.put("qmpPort", 8080);
|
||||
return vmConfigMap;
|
||||
|
|
@ -995,7 +1007,13 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
return;
|
||||
}
|
||||
|
||||
loadConfig(new Gson().fromJson(FileUtils.readFromFile(this, new File(AppConfig.vmFolder + vmID + "/rom-data.json")), DataMainRoms.class));
|
||||
try {
|
||||
loadConfig(new Gson().fromJson(FileUtils.readFromFile(this, new File(AppConfig.vmFolder + vmID + "/rom-data.json")), 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")));
|
||||
|
||||
if (jObj.has("vmID")) {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,13 @@ public class PendingCommand {
|
|||
} else {
|
||||
com.vectras.vm.StartVM.cdrompath = "";
|
||||
Config.vmID = VMManager.idGenerator();
|
||||
String env = StartVM.env(activity, AppConfig.pendingCommand, "", true);
|
||||
MainStartVM.startNow(activity, "Quick run", env, Config.vmID, null);
|
||||
VMManager.lastQemuCommand = AppConfig.pendingCommand;
|
||||
new Thread(() -> {
|
||||
String env = StartVM.env(activity, AppConfig.pendingCommand, "", true);
|
||||
activity.runOnUiThread(() -> {
|
||||
MainStartVM.startNow(activity, "Quick run", env, Config.vmID, null);
|
||||
VMManager.lastQemuCommand = AppConfig.pendingCommand;
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
AppConfig.pendingCommand = "";
|
||||
|
|
|
|||
|
|
@ -50,4 +50,6 @@ public class DataMainRoms {
|
|||
public int bootFrom = 0;
|
||||
|
||||
public boolean isShowBootMenu = false;
|
||||
|
||||
public boolean isUseUefi = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,12 @@ public class VmsFragment extends Fragment implements CallbackInterface.HomeCallT
|
|||
} catch (JSONException ignored) {
|
||||
romsMainData.isShowBootMenu = false;
|
||||
}
|
||||
try {
|
||||
romsMainData.isUseUefi = json_data.getBoolean("isUseUefi");
|
||||
} catch (JSONException ignored) {
|
||||
romsMainData.isUseUefi = false;
|
||||
}
|
||||
|
||||
romsMainData.itemExtra = json_data.getString("imgExtra");
|
||||
tempdata.add(romsMainData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,8 +81,11 @@ public class VmsHomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
|||
Config.QMPPort = current.qmpPort;
|
||||
}
|
||||
Config.vmID = current.vmID;
|
||||
String env = StartVM.env(activity, current);
|
||||
MainStartVM.startNow(activity, current.itemName, env, current.vmID, current.itemIcon);
|
||||
|
||||
new Thread(() -> {
|
||||
String env = StartVM.env(activity, current);
|
||||
activity.runOnUiThread(() -> MainStartVM.startNow(activity, current.itemName, env, current.vmID, current.itemIcon));
|
||||
}).start();
|
||||
});
|
||||
|
||||
myHolder.cdRoms.setOnLongClickListener(v -> {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.io.File;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
|
@ -1047,4 +1048,37 @@ public class FileUtils {
|
|||
Log.e(TAG, "openFolder: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMd5(String filePath) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(filePath);
|
||||
byte[] buffer = new byte[1024];
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
int numRead = 0;
|
||||
while (numRead != -1) {
|
||||
numRead = inputStream.read(buffer);
|
||||
if (numRead > 0)
|
||||
digest.update(buffer, 0, numRead);
|
||||
}
|
||||
byte [] md5Bytes = digest.digest();
|
||||
return convertHashToString(md5Bytes);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String convertHashToString(byte[] md5Bytes) {
|
||||
String returnVal = "";
|
||||
for (byte md5Byte : md5Bytes) {
|
||||
returnVal += Integer.toString((md5Byte & 0xff) + 0x100, 16).substring(1);
|
||||
}
|
||||
return returnVal.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,14 @@ public class NotificationUtils {
|
|||
public static final int NO_ICON = -1;
|
||||
|
||||
public static String generalChannelId = "general";
|
||||
public static String downloadChannelId = "download";
|
||||
|
||||
public static void createAllChannel(Context context) {
|
||||
createChannel("General", "Receive new notifications.",
|
||||
"general", NotificationManager.IMPORTANCE_DEFAULT, context);
|
||||
generalChannelId, NotificationManager.IMPORTANCE_DEFAULT, context);
|
||||
|
||||
createChannel("Download", "View the file download process.",
|
||||
downloadChannelId, NotificationManager.IMPORTANCE_DEFAULT, context);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
|
|
@ -157,6 +161,12 @@ public class NotificationUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void recall(Context context, int id) {
|
||||
if (context == null) return;
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
notificationManager.cancel(id);
|
||||
}
|
||||
|
||||
public static boolean isPermissionGranted(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
return ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
|
||||
|
|
|
|||
76
app/src/main/java/com/vectras/vm/view/CheckBoxView.java
Normal file
76
app/src/main/java/com/vectras/vm/view/CheckBoxView.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package com.vectras.vm.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.vectras.vm.R;
|
||||
|
||||
public class CheckBoxView extends LinearLayout {
|
||||
private TextView tvTitle;
|
||||
private CheckBox checkBox;
|
||||
|
||||
public interface OnCheckedChangeListener {
|
||||
void onCheckedChanged(CheckBoxView view, boolean isChecked);
|
||||
}
|
||||
|
||||
private OnCheckedChangeListener listener;
|
||||
|
||||
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public CheckBoxView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
LayoutInflater.from(context).inflate(R.layout.checkbox_view, this, true);
|
||||
|
||||
tvTitle = findViewById(R.id.tv_title);
|
||||
checkBox = findViewById(R.id.checkbox);
|
||||
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CheckBoxView);
|
||||
|
||||
String title = typedArray.getString(R.styleable.CheckBoxView_setText);
|
||||
boolean isChecked = typedArray.getBoolean(R.styleable.CheckBoxView_setChecked, false);
|
||||
|
||||
if (title != null) tvTitle.setText(title);
|
||||
checkBox.setChecked(isChecked);
|
||||
|
||||
typedArray.recycle();
|
||||
}
|
||||
|
||||
findViewById(R.id.root).setOnClickListener(v -> checkBox.setChecked(!checkBox.isChecked()));
|
||||
|
||||
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (listener != null) {
|
||||
listener.onCheckedChanged(this, isChecked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setText(String title) {
|
||||
tvTitle.setText(title);
|
||||
}
|
||||
|
||||
public void setChecked(boolean isCheck) {
|
||||
checkBox.setChecked(isCheck);
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checkBox.isChecked();
|
||||
}
|
||||
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
findViewById(R.id.root).setEnabled(isEnabled);
|
||||
findViewById(R.id.root).setAlpha(0.5f);
|
||||
checkBox.setEnabled(isEnabled);
|
||||
}
|
||||
}
|
||||
52
app/src/main/java/com/vectras/vm/view/SelectBoxView.java
Normal file
52
app/src/main/java/com/vectras/vm/view/SelectBoxView.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package com.vectras.vm.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.vectras.vm.R;
|
||||
|
||||
public class SelectBoxView extends LinearLayout {
|
||||
|
||||
private TextView tvTitle, tvSubtitle;
|
||||
|
||||
public SelectBoxView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
LayoutInflater.from(context).inflate(R.layout.select_box_view, this, true);
|
||||
|
||||
tvTitle = findViewById(R.id.tv_title);
|
||||
tvSubtitle = findViewById(R.id.tv_subtitle);
|
||||
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SelectBoxView);
|
||||
|
||||
String title = typedArray.getString(R.styleable.SelectBoxView_title);
|
||||
String subtitle = typedArray.getString(R.styleable.SelectBoxView_subtitle);
|
||||
|
||||
if (title != null) tvTitle.setText(title);
|
||||
if (subtitle != null) tvSubtitle.setText(subtitle);
|
||||
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
tvTitle.setText(title);
|
||||
}
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
tvSubtitle.setText(subtitle);
|
||||
}
|
||||
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
findViewById(R.id.root).setEnabled(isEnabled);
|
||||
findViewById(R.id.root).setAlpha(0.5f);
|
||||
}
|
||||
}
|
||||
|
|
@ -266,56 +266,24 @@
|
|||
android:paddingBottom="8dp"
|
||||
android:text="@string/boot" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_bootfrom"
|
||||
<com.vectras.vm.view.SelectBoxView
|
||||
android:id="@+id/sbv_bootfrom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/boot_from"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_bootfrom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/defaulttext" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/keyboard_arrow_right_24px" />
|
||||
</LinearLayout>
|
||||
app:title="@string/boot_from"
|
||||
app:subtitle="@string/defaulttext" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_showbootmenu"
|
||||
<com.vectras.vm.view.CheckBoxView
|
||||
android:id="@+id/cbv_showbootmenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/show_boot_menu" />
|
||||
<CheckBox
|
||||
android:id="@+id/cb_showbootmenu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false"/>
|
||||
</LinearLayout>
|
||||
app:setText="@string/show_boot_menu"/>
|
||||
|
||||
<com.vectras.vm.view.CheckBoxView
|
||||
android:id="@+id/cbv_useuefi"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:setText="@string/use_uefi_for_x64_only"/>
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
|
|||
22
app/src/main/res/layout/checkbox_view.xml
Normal file
22
app/src/main/res/layout/checkbox_view.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Text" />
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -195,6 +195,78 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/tools"
|
||||
android:textColor="?attr/colorControlNormal"
|
||||
android:textSize="22sp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_virtio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/deployed_code_24px"/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="?attr/colorControlNormal"
|
||||
android:text="@string/virtio_tools_for_windows"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_ejectvirtio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/eject_24px"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_3dfx"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/deployed_code_24px"/>
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:layout_weight="1"
|
||||
android:textColor="?attr/colorControlNormal"
|
||||
android:text="@string/threedfx_wrappers"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_eject3dfx"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/eject_24px"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_user_interface"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
36
app/src/main/res/layout/select_box_view.xml
Normal file
36
app/src/main/res/layout/select_box_view.xml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Title"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Subtitle" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/keyboard_arrow_right_24px" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -524,6 +524,14 @@
|
|||
<string name="tap_to_view">Chạm để xem.</string>
|
||||
<string name="view_in_an_bui_app">Xem trong ứng dụng An Bùi</string>
|
||||
<string name="view_in_an_bui_app_note">Bạn có thể xem và lấy nó ở đây.</string>
|
||||
<string name="tools">Công cụ</string>
|
||||
<string name="threedfx_wrappers">Trình bao bọc 3dfx</string>
|
||||
<string name="virtio_tools_for_windows">Công cụ VirtIO cho Windows</string>
|
||||
<string name="download_required">Càn tải xuống</string>
|
||||
<string name="this_tool_needs_to_be_downloaded_before_use">Công cụ này cần được tải xuống để sử dụng. Bạn sẽ được thông báo khi quá trình tải xuống hoàn thành.</string>
|
||||
<string name="download_failed_note">Tải xuống thất bại. Hãy thử lại sau.</string>
|
||||
<string name="virtio_tools_for_windows_is_now_ready_to_use">Công cụ VirtIO cho Windows đã sẵn sàng để sử dụng</string>
|
||||
<string name="do_you_want_to_insert_it_into_the_optical_drive_right_now">Bạn có muốn gắn nó vào ổ đĩa quang ngay không?</string>
|
||||
|
||||
|
||||
<!--======================TERMUX STRINGS====================-->
|
||||
|
|
|
|||
|
|
@ -37,4 +37,14 @@
|
|||
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SelectBoxView">
|
||||
<attr name="title" format="string"/>
|
||||
<attr name="subtitle" format="string"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CheckBoxView">
|
||||
<attr name="setText" format="string"/>
|
||||
<attr name="setChecked" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
|
@ -533,6 +533,14 @@
|
|||
<string name="tap_to_view">Tap to view.</string>
|
||||
<string name="view_in_an_bui_app">View in the An Bui app</string>
|
||||
<string name="view_in_an_bui_app_note">You can view and get it here.</string>
|
||||
<string name="tools">Tools</string>
|
||||
<string name="threedfx_wrappers">3dfx wrappers</string>
|
||||
<string name="virtio_tools_for_windows">VirtIO tools for Windows</string>
|
||||
<string name="download_required">Download required</string>
|
||||
<string name="this_tool_needs_to_be_downloaded_before_use">This tool needs to be downloaded before use. You will be notified when the download is complete.</string>
|
||||
<string name="download_failed_note">Download failed. Please try again later.</string>
|
||||
<string name="virtio_tools_for_windows_is_now_ready_to_use">VirtIO tools for Windows is now ready to use</string>
|
||||
<string name="do_you_want_to_insert_it_into_the_optical_drive_right_now">Do you want to insert it into the optical drive right now?</string>
|
||||
|
||||
|
||||
<!--======================TERMUX STRINGS====================-->
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
|
||||
"Message": "<h2>3.9.0</h2>\nBugs fixed.",
|
||||
"cancellable": true,
|
||||
"versionCodeBeta":"95",
|
||||
"versionNameBeta":"3.9.1",
|
||||
"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",
|
||||
"versionCodeBeta":"96",
|
||||
"versionNameBeta":"3.9.2",
|
||||
"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",
|
||||
"sizeBeta": "45 MB",
|
||||
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
|
||||
"MessageBeta": "<h2>3.9.1</h2>Bugs fixed.",
|
||||
"MessageBeta": "<h2>3.9.2</h2>Bugs fixed.",
|
||||
"cancellableBeta": true
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue