- Fixed the hidden navigation bar and create button when returning to the virtual machine list.
- Added another tap on Rom store or Software & driver in the navigation bar to open search.
- Fixed the issue of content reloading when tapping any item in the navigation bar multiple times.
- Fixed the slow loading of the virtual machine list.
- Fixed the System monitor error when performing actions too quickly.
- Fixed the Home screen error when performing actions too quickly.
- Fixed the Setup Wizard potentially becoming unresponsive during the System File Installation step.
- Fixed the VNC settings and removable device control dialog box causing unresponsiveness on the VNC screen.
This commit is contained in:
An Bui 2025-12-21 00:14:34 +07:00
parent c937d03c2c
commit ad47dfb60e
10 changed files with 271 additions and 136 deletions

View file

@ -15,8 +15,8 @@ android {
applicationId "com.vectras.vm"
minSdk minApi
targetSdk targetApi
versionCode 51
versionName "3.4.7"
versionCode 52
versionName "3.4.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true

View file

@ -835,11 +835,11 @@ public class VMManager {
}
public static void shutdownCurrentVM() {
QmpClient.sendCommand("{ \"execute\": \"quit\" }");
new Thread(() -> QmpClient.sendCommand("{ \"execute\": \"quit\" }")).start();
}
public static void resetCurrentVM() {
QmpClient.sendCommand("{ \"execute\": \"system_reset\" }");
new Thread(() -> QmpClient.sendCommand("{ \"execute\": \"system_reset\" }")).start();
}
public static void showChangeRemovableDevicesDialog(Activity _activity, VncCanvasActivity vncCanvasActivity) {
@ -1028,135 +1028,155 @@ public class VMManager {
}
public static void changeCDROM(String _path, Activity _activity) {
if (isUsingQ35(lastQemuCommand)) {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("ide2-cd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
new Thread(() -> {
if (isUsingQ35(lastQemuCommand)) {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("ide2-cd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("ide1-cd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
}
} else {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("ide1-cd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
}
}
}).start();
}
public static void changeFloppyDriveA(String _path, Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("floppy0", _path)))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("floppy0", _path)))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void changeFloppyDriveB(String _path, Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("floppy1", _path)))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("floppy1", _path)))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void changeSDCard(String _path, Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("sd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(changeRemovableDevicesQMPCommand("sd0", _path)))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void ejectCDROM(Activity _activity) {
if (isUsingQ35(lastQemuCommand)) {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("ide2-cd0")))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
new Thread(() -> {
if (isUsingQ35(lastQemuCommand)) {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("ide2-cd0")))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("ide1-cd0")))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
}
} else {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("ide1-cd0")))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
}
}
}).start();
}
public static void ejectFloppyDriveA(Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("floppy0")))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("floppy0")))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void ejectFloppyDriveB(Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("floppy1")))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("floppy1")))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void ejectSDCard(Activity _activity) {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("sd0")))) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
}
new Thread(() -> {
if (isQMPCommandSuccess(QmpClient.sendCommand(ejectRemovableDevicesQMPCommand("sd0")))) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
}).start();
}
public static void changeRemovableDevice(String _deviceID, String _filepath, Activity _activity) {
String _result = QmpClient.sendCommand(changeRemovableDevicesQMPCommand(_deviceID, _filepath));
if (isQMPCommandSuccess(_result)) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing()) {
if (_result.contains("is not removable")) {
Toast.makeText(_activity, _activity.getString(R.string.this_is_not_a_removable_device), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show();
new Thread(() -> {
String _result = QmpClient.sendCommand(changeRemovableDevicesQMPCommand(_deviceID, _filepath));
if (isQMPCommandSuccess(_result)) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.changed), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing()) {
if (_result.contains("is not removable")) {
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.this_is_not_a_removable_device), Toast.LENGTH_SHORT).show());
} else {
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.change_failed), Toast.LENGTH_SHORT).show());
}
}
}
}
}).start();
}
public static void ejectRemovableDevice(String _deviceID, Activity _activity) {
String _result = QmpClient.sendCommand(ejectRemovableDevicesQMPCommand(_deviceID));
if (isQMPCommandSuccess(_result)) {
if (_activity != null && !_activity.isFinishing())
Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show();
} else {
if (_activity != null && !_activity.isFinishing()) {
if (_result.contains("is not removable")) {
Toast.makeText(_activity, _activity.getString(R.string.this_is_not_a_removable_device), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show();
new Thread(() -> {
String _result = QmpClient.sendCommand(ejectRemovableDevicesQMPCommand(_deviceID));
if (isQMPCommandSuccess(_result)) {
if (_activity != null && !_activity.isFinishing())
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.ejected), Toast.LENGTH_SHORT).show());
} else {
if (_activity != null && !_activity.isFinishing()) {
if (_result.contains("is not removable")) {
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.this_is_not_a_removable_device), Toast.LENGTH_SHORT).show());
} else {
_activity.runOnUiThread(() -> Toast.makeText(_activity, _activity.getString(R.string.eject_failed), Toast.LENGTH_SHORT).show());
}
}
}
}
}).start();
}
public static void setVNCPasswordWithDelay(String _password) {

View file

@ -24,12 +24,16 @@ import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.GravityCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.behavior.HideViewOnScrollBehavior;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
import com.termux.app.TermuxActivity;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainSettingsManager;
@ -84,6 +88,7 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
private final String TAG = "HomeActivity";
private final int SEARCH_ROM_STORE = 0;
private final int SEARCH_SOFTWARE_STORE = 1;
private int currentBottomBarSelectedItemId = 0;
private int currentSearchMode = 0;
public static boolean isActivate = false;
public static boolean isNeedRecreate = false;
@ -185,6 +190,14 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
Fragment selectedFragment;
int id = item.getItemId();
if (id == currentBottomBarSelectedItemId) {
if (id == R.id.item_romstore || id == R.id.item_softwarestore) {
if (bindingContent.searchbar.isEnabled()) binding.searchview.show();
}
return true;
}
if (id == R.id.item_home) {
selectedFragment = new VmsFragment();
bindingContent.efabCreate.setVisibility(View.VISIBLE);
@ -221,9 +234,12 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
getSupportFragmentManager().beginTransaction()
.replace(bindingContent.containerView.getId(), selectedFragment)
.commit();
currentBottomBarSelectedItemId = id;
return true;
});
currentBottomBarSelectedItemId = bindingContent.bottomNavigation.getSelectedItemId();
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
@ -236,6 +252,7 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
binding.searchview.hide();
} else if (bindingContent.bottomNavigation.getSelectedItemId() != R.id.item_home) {
bindingContent.bottomNavigation.setSelectedItemId(R.id.item_home);
showBottomBarAndFab();
} else if (MainSettingsManager.getQuickStart(MainActivity.this)) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
@ -339,6 +356,7 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
isOpenHome = false;
if (binding.searchview.isShowing()) binding.searchview.hide();
bindingContent.bottomNavigation.setSelectedItemId(R.id.item_home);
showBottomBarAndFab();
}
new Handler(Looper.getMainLooper()).post(() -> DisplaySystem.startTermuxX11(this));
@ -398,6 +416,30 @@ public class MainActivity extends AppCompatActivity implements RomStoreFragment.
});
}
private void showBottomBarAndFab() {
bindingContent.bottomNavigation.post(() -> {
CoordinatorLayout.LayoutParams lp =
(CoordinatorLayout.LayoutParams) bindingContent.bottomNavigation.getLayoutParams();
HideViewOnScrollBehavior<BottomNavigationView> behavior = (HideViewOnScrollBehavior<BottomNavigationView>) lp.getBehavior();
if (behavior != null) {
behavior.slideIn(bindingContent.bottomNavigation);
}
});
bindingContent.efabCreate.post(() -> {
CoordinatorLayout.LayoutParams lpfab =
(CoordinatorLayout.LayoutParams) bindingContent.efabCreate.getLayoutParams();
HideViewOnScrollBehavior<ExtendedFloatingActionButton> behaviorfab = (HideViewOnScrollBehavior<ExtendedFloatingActionButton>) lpfab.getBehavior();
if (behaviorfab != null) {
behaviorfab.slideIn(bindingContent.efabCreate);
}
});
}
private void updateApp() {
int versionCode = PackageUtils.getThisVersionCode(getApplicationContext());
// String versionName = PackageUtils.getThisVersionName(getApplicationContext());

View file

@ -206,6 +206,7 @@ public class SystemMonitorFragment extends Fragment {
executor.execute(() -> {
String qemuVersionName = CommandUtils.getQemuVersionName();
if (!isAdded()) return;
String result = Terminal.executeShellCommandWithResult("ps -e command", requireActivity());
requireActivity().runOnUiThread(() -> {
binding.tvProcesses.setText(result);
@ -242,6 +243,7 @@ public class SystemMonitorFragment extends Fragment {
@SuppressLint("SetTextI18n")
private void getVNCServerStatus(String resultCommand) {
if (!isAdded()) return;
binding.tvVncport.setText(getString(R.string.port_qemu) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(requireActivity())) + 5900) + ".");
if (resultCommand.contains(Config.defaultVNCHost + ":" + Config.defaultVNCPort)) {

View file

@ -108,6 +108,8 @@ public class VmsFragment extends Fragment implements CallbackInterface.HomeCallT
List<DataMainRoms> tempdata = new ArrayList<>();
try {
if (!isAdded()) return;
jArray = new JSONArray(FileUtils.readFromFile(requireActivity(), new File(AppConfig.maindirpath
+ "roms-data.json")));
@ -146,12 +148,15 @@ public class VmsFragment extends Fragment implements CallbackInterface.HomeCallT
romsMainData.itemExtra = json_data.getString("imgExtra");
tempdata.add(romsMainData);
}
if (!isAdded()) return;
requireActivity().runOnUiThread(() -> binding.lnError.setVisibility(View.GONE));
} catch (JSONException e) {
if (!isAdded()) return;
requireActivity().runOnUiThread(() -> binding.lnError.setVisibility(View.VISIBLE));
Log.e(TAG, "loadDataVbi: ", e);
}
if (!isAdded()) return;
requireActivity().runOnUiThread(() -> {
binding.lnLoad.setVisibility(View.GONE);
if (tempdata.isEmpty()) {
@ -167,27 +172,32 @@ public class VmsFragment extends Fragment implements CallbackInterface.HomeCallT
}
private void checkAndLoad() {
if (!isAdded()) return;
if (PermissionUtils.storagepermission(requireActivity(), true)) {
loadDataVbi();
if (DeviceUtils.isStorageLow(requireActivity(), true)) {
DialogUtils.oneDialog(requireActivity(),
getResources().getString(R.string.oops),
getResources().getString(R.string.very_low_available_storage_space_content),
getResources().getString(R.string.ok),
true,
R.drawable.warning_48px,
true,
null,
() -> {
if (DeviceUtils.isStorageLow(requireActivity(), true))
requireActivity().finish();
});
}
executor.execute(() -> {
if (DeviceUtils.isStorageLow(requireActivity(), true)) {
if (!isAdded()) return;
requireActivity().runOnUiThread(() -> DialogUtils.oneDialog(requireActivity(),
getResources().getString(R.string.oops),
getResources().getString(R.string.very_low_available_storage_space_content),
getResources().getString(R.string.ok),
true,
R.drawable.warning_48px,
true,
null,
() -> {
if (DeviceUtils.isStorageLow(requireActivity(), true))
requireActivity().finish();
}));
}
});
}
}
@Override
public void refeshVMList() {
if (!isAdded()) return;
requireActivity().runOnUiThread(this::checkAndLoad);
}

View file

@ -58,6 +58,8 @@ import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SetupWizard2Activity extends AppCompatActivity {
ActivitySetupWizard2Binding binding;
@ -86,6 +88,7 @@ public class SetupWizard2Activity extends AppCompatActivity {
boolean isNotEnoughStorageSpace = false;
boolean isCustomSetupMode = false;
final ArrayList<HashMap<String, String>> mirrorList = new ArrayList<>();
ExecutorService executor = Executors.newSingleThreadExecutor();
@Override
@ -346,26 +349,29 @@ public class SetupWizard2Activity extends AppCompatActivity {
}
private void extractSystemFiles() {
isNotEnoughStorageSpace = DeviceUtils.isStorageLow(this, false);
uiController(STEP_EXTRACTING_SYSTEM_FILES);
if (isNotEnoughStorageSpace) {
uiController(STEP_ERROR);
return;
} else {
uiController(STEP_EXTRACTING_SYSTEM_FILES);
}
new Thread(() -> {
boolean result = SetupFeatureCore.startExtractSystemFiles(this);
runOnUiThread(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (result) {
getDataForStandardSetup();
} else {
uiController(STEP_ERROR, getString(R.string.system_files_installation_failed_content) + (!SetupFeatureCore.lastErrorLog.isEmpty() ? "\n\n" + SetupFeatureCore.lastErrorLog : ""));
executor.execute(() -> {
isNotEnoughStorageSpace = DeviceUtils.isStorageLow(this, false);
runOnUiThread(() -> {
if (isNotEnoughStorageSpace) {
uiController(STEP_ERROR);
return;
}
}, 1000));
}).start();
new Thread(() -> {
boolean result = SetupFeatureCore.startExtractSystemFiles(this);
runOnUiThread(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (result) {
getDataForStandardSetup();
} else {
uiController(STEP_ERROR, getString(R.string.system_files_installation_failed_content) + (!SetupFeatureCore.lastErrorLog.isEmpty() ? "\n\n" + SetupFeatureCore.lastErrorLog : ""));
}
}, 1000));
}).start();
});
});
}
private void getDataForStandardSetup() {

View file

@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
tools:context=".main.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"

View file

@ -16,6 +16,7 @@
android:id="@+id/rv_romlist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:clipToPadding="false"
tools:listitem="@layout/container_main_roms" />

View file

@ -5,11 +5,11 @@
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
"Message": "<h2>3.4.0</h2>\n- Fixed the issue of exporting rom with virtual machine ID.\n- New dialog for copying files in creating new virtual machine.\n- New dialog showing information after successful rom import.\n- Fixed no sound playing with Termux.\n- Fixed invalid file path error when using Manual setup.\n- Fixed dialog showing content without line breaks.\n- Fixed rom export error.\n- Added Processes to System monitor.\n- Improved interface.\n- Thinner fonts.\n- Fixed an issue with interaction in Rom store.\n- Fixed the External VNC Server switch being incorrect in certain cases.\n- Removed unnecessary resources.\n- Updated Chinese (Simplified) language (contributed by @WeiguangTWK).\n- Fixed issue with installing system files after not completing the first time.\n- New setup wizard.\n- Added auto return to Home after importing rom and creating virtual machine in Rom store.\n- Improved image viewer.\n- Fixed Unknow display error in architecture in rom info if it is PowerPC architecture.\n- New setup wizard interface that automatically changes according to screen size.\n- New ID generator for virtual machine.\n- Added dialog when deleting virtual machine.",
"cancellable": true,
"versionCodeBeta":"51",
"versionNameBeta":"3.4.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",
"sizeBeta": "45 MB",
"versionCodeBeta":"52",
"versionNameBeta":"3.4.8",
"versionNameBetas":"3.0.0,3.1.0,3.2.1,3.2.2,3.2.3,3.2.4,3.2.5,3.2.6,3.2.7,3.2.8,3.2.9,3.2.10,3.3.1,3.3.2,3.3.3,3.3.4,3.3.5,3.3.6,3.3.7,3.3.8,3.3.9,3.4.1,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8",
"sizeBeta": "46 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>3.4.7</h2>Bugs fixed.",
"MessageBeta": "<h2>3.4.8</h2>Bugs fixed.",
"cancellableBeta": true
}

View file

@ -52,6 +52,60 @@
"verified": true,
"vecid": "3dfxwrappers295iso",
"id": ""
},
{
"rom_name": "7-Zip",
"rom_icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/7-Zip_Icon.svg/2560px-7-Zip_Icon.svg.png",
"rom_url": "https://archive.org/details/7-zip_202512",
"rom_path": "7Zip.iso",
"rom_avail": true,
"rom_size": "24.09 (x64)",
"rom_arch": "X86_64",
"rom_kernel": "",
"rom_extra": "",
"final_rom_file_name": "",
"desc": "7-Zip is a free and open-source file archiver, a utility used to place groups of files within compressed containers known as archives.",
"file_size": "2 MB",
"creator": "tokaevUser",
"verified": true,
"vecid": "7zipiso",
"id": ""
},
{
"rom_name": "AIDA64",
"rom_icon": "https://store-images.microsoft.com/image/apps.3123.13510798884987542.689d0953-1168-4bc4-8942-23b988b99331.cb456ed4-e854-4ade-b494-f3ebe3f7cfe5",
"rom_url": "https://archive.org/details/aida64_202512",
"rom_path": "aida64.iso",
"rom_avail": true,
"rom_size": "7.60",
"rom_arch": "X86_64",
"rom_kernel": "",
"rom_extra": "",
"final_rom_file_name": "",
"desc": "AIDA64, industry-leading system information, diagnostics & benchmarking software with advanced hardware monitoring and detailed system reports.",
"file_size": "100 MB",
"creator": "tokaevUser",
"verified": true,
"vecid": "aida64iso",
"id": ""
},
{
"rom_name": "Counter-Strike",
"rom_icon": "https://upload.wikimedia.org/wikipedia/en/6/67/Counter-Strike_Box.jpg?20201215232736",
"rom_url": "https://archive.org/details/cs-1.6_202512",
"rom_path": "cs 1.6.iso",
"rom_avail": true,
"rom_size": "1.6",
"rom_arch": "X86_64",
"rom_kernel": "",
"rom_extra": "",
"final_rom_file_name": "",
"desc": "Counter-Strike (also known as Half-Life: Counter-Strike or Counter-Strike 1.6) is a 2000 tactical first-person shooter game developed by Valve Corporation and published by Sierra Studios. It is the first installment in the Counter-Strike series.",
"file_size": "200 MB",
"creator": "tokaevUser",
"verified": true,
"vecid": "cs16iso",
"id": ""
}
]