From 09f9654ccd4ff423549843644a3565803cd1fee2 Mon Sep 17 00:00:00 2001 From: An Bui <91354810+AnBui2004@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:13:21 +0700 Subject: [PATCH] 4.2.4 - Faster return to virtual machine. - Fixed the frozen virtual machine startup dialog when using X11. - Added audio support for the built-in X11 display. - Improved notifications. - Qemu 7.2.22 has been improved and requires manual updating with the Upgrade tool using a command in the Terminal. --- .github/ISSUE_TEMPLATE/bug.yaml | 1 + README.md | 2 +- app/build.gradle | 4 +- app/src/main/java/com/vectras/vm/StartVM.java | 2 + .../java/com/vectras/vm/fcm/FCMService.java | 9 +- .../com/vectras/vm/main/core/MainStartVM.java | 91 +++++++-- .../java/com/vectras/vm/x11/X11Activity.java | 192 +++++++++++------- .../layout/activity_x11_display_settings.xml | 19 ++ app/src/main/res/values-vi/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + js/push_notification.js | 5 +- qemu/7.2.22/upgrade.sh | 2 +- web/data/UpdateConfig.json | 8 +- 13 files changed, 239 insertions(+), 98 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 17c03f6..1e7cf9c 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -32,6 +32,7 @@ body: options: - Latest - Beta + - 4.2.0 - 4.1.0 - 4.0.0 - 3.9.0 diff --git a/README.md b/README.md index 88c741e..8785173 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ QEMU 8.2.0 - 3dfx (only for Vectras VM 2.9.5): - [See them at the Internet Archive](https://archive.org/details/vectras-vm-x86_64.tar_202603nbab) QEMU 7.2.22 - 3dfx (for Vectras VM 4.2.2+): -- [For Android ARM (64-bit)](https://archive.org/download/qemu-7-2-22-for-vectras-vm-nbab/base-vectras-vm-arm64-v8a.tar.gz) +- [For Android ARM (64-bit)](https://archive.org/download/qemu-7-2-22-for-vectras-vm-nbab/base-june-2026-vectras-vm-arm64-v8a.tar.gz) - [See more at the Internet Archive](https://archive.org/details/qemu-7-2-22-for-vectras-vm-nbab) ### 💽 3Dfx Wrappers diff --git a/app/build.gradle b/app/build.gradle index d6aead5..c492ebe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi - versionCode 127 - versionName "4.2.3" + versionCode 128 + versionName "4.2.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true diff --git a/app/src/main/java/com/vectras/vm/StartVM.java b/app/src/main/java/com/vectras/vm/StartVM.java index a4743bf..0a95509 100644 --- a/app/src/main/java/com/vectras/vm/StartVM.java +++ b/app/src/main/java/com/vectras/vm/StartVM.java @@ -28,6 +28,8 @@ public class StartVM { private static DataMainRoms vmConfigs; public static String env(Activity activity, DataMainRoms vmData) { + if (VMManager.isVMRunning(activity, vmData.vmID)) return ""; + vmConfigs = vmData; if (VMManager.isNeedLoadMigrate() && FileUtils.isFileExists(VmFileManager.getSnapshotSh(Config.vmID))) { diff --git a/app/src/main/java/com/vectras/vm/fcm/FCMService.java b/app/src/main/java/com/vectras/vm/fcm/FCMService.java index 94082d3..6188e01 100644 --- a/app/src/main/java/com/vectras/vm/fcm/FCMService.java +++ b/app/src/main/java/com/vectras/vm/fcm/FCMService.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import com.vectras.vm.R; +import com.vectras.vm.settings.UpdaterActivity; import com.vectras.vm.utils.NotificationUtils; import java.util.Map; @@ -21,6 +22,12 @@ public class FCMService && !Objects.requireNonNull(data.get("targetVersions")).contains(getString(R.string.app_version))) { return; } + + Class activityClass = null; + + if (data.get("activityClass") != null) { + if (Objects.equals(data.get("activityClass"), "update")) activityClass = UpdaterActivity.class; + } NotificationUtils.pushNow(this, 1, @@ -31,7 +38,7 @@ public class FCMService data.get("image") != null ? data.get("image") : null, -1, data.get("url") != null ? data.get("url") : null, - null); + activityClass); } @Override diff --git a/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java b/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java index a6ad183..64b25fa 100644 --- a/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java +++ b/app/src/main/java/com/vectras/vm/main/core/MainStartVM.java @@ -14,7 +14,6 @@ import android.widget.Toast; import com.vectras.qemu.Config; import com.vectras.qemu.MainSettingsManager; import com.vectras.qemu.MainVNCActivity; -import com.vectras.vm.AppConfig; import com.vectras.vm.MainService; import com.vectras.vm.R; import com.vectras.vm.StartVM; @@ -55,6 +54,26 @@ public class MainStartVM { private static StartVmDialog dialog; + public static final int PENDDING_EMPTY = -1; + + public static final int STARTED_VM = 0; + public static final int STARTED_VM_READY_RUNNING = 1; + + public static final int ERROR_VM = 10; + public static final int ERROR_BREAK = 11; + public static final int ERROR_INVALID_VM_ID = 12; + public static final int ERROR_MAKE_TEMP_FOLDER = 13; + public static final int ERROR_UNSAFE_COMMAND = 14; + public static final int ERROR_ACCEL = 15; + public static final int ERROR_VNC_TCP_PORT = 16; + public static final int ERROR_SHARED_FOLDER = 17; + public static final int ERROR_RESUME = 18; + + public interface MainStartVMCallback { + void onStarted(int statusCode, String message); + void onError(int errorCode, String message); + } + public static void startNow(Activity activity, DataMainRoms vmConfig) { breakNow = false; @@ -62,7 +81,10 @@ public class MainStartVM { VMManager.setArch(vmConfig.itemArch, activity); - if (!(MainSettingsManager.getVmUi(activity).equals("X11") && DisplaySystem.isUseBuiltInX11())) { + if ( + MainSettingsManager.getVmUi(activity).equals("VNC") || + (MainSettingsManager.getVmUi(activity).equals("X11") && !DisplaySystem.isUseBuiltInX11()) + ) { showDialog(activity, vmConfig.vmID, vmConfig.itemName, vmConfig.itemIcon, activity.getString(R.string.preparing)); } @@ -82,9 +104,22 @@ public class MainStartVM { String thumbnailFile, StartVmDialog dialog ) { + startNow(context, vmName, env, vmID, thumbnailFile, dialog, null); + } + + public static void startNow( + Context context, + String vmName, + String env, + String vmID, + String thumbnailFile, + StartVmDialog dialog, + MainStartVMCallback callback + ) { if (breakNow) { breakNow = false; + if (callback != null) callback.onError(PENDDING_EMPTY, ""); return; } @@ -92,7 +127,10 @@ public class MainStartVM { if (isLaunchFromPending) { isLaunchFromPending = false; - if (pendingVMID.isEmpty()) return; + if (pendingVMID.isEmpty()) { + if (callback != null) callback.onError(ERROR_INVALID_VM_ID, ""); + return; + } pendingVMID = ""; } else { if (MainSettingsManager.getVmUi(context).equals("X11") && !DisplaySystem.isUseBuiltInX11()) { @@ -128,8 +166,6 @@ public class MainStartVM { breakNow = false; - if (dialog == null || !dialog.isShowing()) showDialog((Activity) context, vmID, vmName, thumbnailFile, null); - String finalvmID; if (vmID == null || vmID.isEmpty()) { finalvmID = VMManager.startRamdomVMID(); @@ -140,14 +176,23 @@ public class MainStartVM { Config.vmID = finalvmID; if (VMManager.isVMRunning(context, finalvmID)) { - Toast.makeText(context, "This VM is already running.", Toast.LENGTH_LONG).show(); - DisplaySystem.launch(context); - if (!MainSettingsManager.getVmUi(context).equals("VNC")) VmAudioManager.stream(vmID); - dismissDialog(); + + Toast.makeText(context, context.getString(R.string.this_vm_is_already_running), Toast.LENGTH_LONG).show(); + DisplaySystem.launch(context); + if ( + !MainSettingsManager.getVmUi(context).equals("VNC") && + !DisplaySystem.isUseBuiltInX11() + ) + VmAudioManager.stream(vmID); + + if (callback != null) callback.onStarted(STARTED_VM_READY_RUNNING, ""); return; } + // Place it here to avoid freezing when the dialog box appears upon returning to the virtual machine. + if (dialog == null || !dialog.isShowing()) showDialog((Activity) context, vmID, vmName, thumbnailFile, null); + File romDir = new File(Config.getCacheDir() + "/" + finalvmID); if (!romDir.exists()) { if (!romDir.mkdirs()) { @@ -159,6 +204,7 @@ public class MainStartVM { ); dismissDialog(); + if (callback != null) callback.onError(ERROR_MAKE_TEMP_FOLDER, ""); return; } } @@ -172,6 +218,7 @@ public class MainStartVM { ); dismissDialog(); + if (callback != null) callback.onError(ERROR_UNSAFE_COMMAND, ""); return; } @@ -182,6 +229,7 @@ public class MainStartVM { () -> startNow(context, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), finalvmID, thumbnailFile, finalDialog1), null, null); dismissDialog(); + if (callback != null) callback.onError(ERROR_ACCEL, ""); return; } } @@ -198,6 +246,7 @@ public class MainStartVM { null); dismissDialog(); + if (callback != null) callback.onError(ERROR_VNC_TCP_PORT, ""); return; } @@ -221,6 +270,7 @@ public class MainStartVM { ); dismissDialog(); + if (callback != null) callback.onError(ERROR_SHARED_FOLDER, ""); return; } @@ -228,10 +278,11 @@ public class MainStartVM { if (breakNow) { dismissDialog(); + if (callback != null) callback.onError(ERROR_BREAK, ""); return; } - startVm(context, vmName, env, finalvmID, thumbnailFile); + startVm(context, vmName, env, finalvmID, thumbnailFile, callback); }); }).start(); } @@ -241,7 +292,8 @@ public class MainStartVM { String vmName, String env, String vmID, - String thumbnailFile + String thumbnailFile, + MainStartVMCallback callback ) { VMManager.isQemuStopedWithError = false; @@ -257,6 +309,7 @@ public class MainStartVM { if (breakNow) { dismissDialog(); + if (callback != null) callback.onError(ERROR_BREAK, ""); return; } @@ -332,6 +385,8 @@ public class MainStartVM { null, null ); + + if (callback != null) callback.onError(ERROR_RESUME, ""); }); return; @@ -372,12 +427,18 @@ public class MainStartVM { Log.i(TAG, "Virtual machine running."); if (activity != null) { - activity.runOnUiThread(MainStartVM::dismissDialog); + activity.runOnUiThread(() -> { + MainStartVM.dismissDialog(); + if (callback != null) callback.onStarted(STARTED_VM, ""); + }); } }).start(); } else { assert activity != null; - activity.runOnUiThread(MainStartVM::dismissDialog); + activity.runOnUiThread(() -> { + MainStartVM.dismissDialog(); + if (callback != null) callback.onError(ERROR_VM, ""); + }); } skipIDEwithARM64DialogInStartVM = false; @@ -404,9 +465,9 @@ public class MainStartVM { VMManager.isTryAgain = false; } - public static void startPending(Context context) { + public static void startPending(Context context, MainStartVMCallback callback) { isLaunchFromPending = true; - startNow(context, pendingVMName, pendingEnv, pendingVMID, pendingThumbnailFile, null); + startNow(context, pendingVMName, pendingEnv, pendingVMID, pendingThumbnailFile, null, callback); } private static void showDialog(Activity activity, String vmId, String vmName, String thumbnailPath, String status) { diff --git a/app/src/main/java/com/vectras/vm/x11/X11Activity.java b/app/src/main/java/com/vectras/vm/x11/X11Activity.java index 249d735..674047f 100644 --- a/app/src/main/java/com/vectras/vm/x11/X11Activity.java +++ b/app/src/main/java/com/vectras/vm/x11/X11Activity.java @@ -3,18 +3,19 @@ package com.vectras.vm.x11; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import android.app.Dialog; + import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION.SDK_INT; import android.content.pm.PackageManager; import android.os.Looper; + import static android.view.InputDevice.KEYBOARD_TYPE_ALPHABETIC; import static android.view.KeyEvent.*; import static android.view.WindowManager.LayoutParams.*; import android.view.WindowManager; -import androidx.activity.OnBackPressedCallback; import androidx.appcompat.content.res.AppCompatResources; import androidx.fragment.app.FragmentTransaction; @@ -28,6 +29,9 @@ import com.vectras.vm.databinding.DesktopControlsBinding; import com.vectras.vm.databinding.GameControlsBinding; import com.vectras.vm.main.core.MainStartVM; import com.vectras.vm.manager.QmpSender; +import com.vectras.vm.manager.VmAudioManager; +import com.vectras.vm.manager.VmFileManager; +import com.vectras.vm.utils.StreamAudio; import com.vectras.vm.utils.UIUtils; import static com.vectras.vm.x11.CmdEntryPoint.ACTION_START; @@ -119,6 +123,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow public boolean ctrlClicked = false; public boolean altClicked = false; + private StreamAudio streamAudio; + ActivityX11Binding binding; ControlsFragmentBinding bindingControls; DesktopControlsBinding bindingDesktopControls; @@ -178,11 +184,11 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow @Override @SuppressLint({ - "AppCompatMethod", - "ObsoleteSdkInt", - "ClickableViewAccessibility", - "WrongConstant", - "UnspecifiedRegisterReceiverFlag" + "AppCompatMethod", + "ObsoleteSdkInt", + "ClickableViewAccessibility", + "WrongConstant", + "UnspecifiedRegisterReceiverFlag" }) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -281,8 +287,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow } if (e.getScanCode() == KEY_BACK - && e.getDevice().getKeyboardType() - != KEYBOARD_TYPE_ALPHABETIC + && e.getDevice().getKeyboardType() + != KEYBOARD_TYPE_ALPHABETIC || e.getScanCode() == 0) { if (toggleIMEUsingBackKey && e.getAction() == ACTION_UP) { Log.d(TAG, "KEYCODE_BACK: toggleIMEUsingBackKey"); @@ -688,31 +694,49 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow bindingDesktopControls.ctrlaltdelBtn.setVisibility(View.GONE); - MainStartVM.startPending(this); + MainStartVM.startPending(this, new MainStartVM.MainStartVMCallback() { + @Override + public void onStarted(int statusCode, String message) { + MainStartVM.dismissDialog(); + setupSound(); + } + + @Override + public void onError(int errorCode, String message) { + MainStartVM.dismissDialog(); + if (errorCode == MainStartVM.PENDDING_EMPTY) setupSound(); + } + } + ); } private void onBack() { if (bindingControls.mainControl.getVisibility() == View.GONE) { bindingControls.mainControl.setVisibility(View.VISIBLE); } else { + if (streamAudio != null) { + if (!VmAudioManager.currentVmId.equals(Config.vmID)) streamAudio.setCross(null); + if (streamAudio.isPlaying()) streamAudio.stop(); + } finish(); } } - + private void keyDownUp(int keyEventCode) { dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode)); } - + private void sendKey(int keyEventCode, boolean up) { if (up) dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode)); else dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); } - + @Override protected void onDestroy() { unregisterReceiver(receiver); + if (streamAudio != null) streamAudio.stop(); super.onDestroy(); } @@ -790,7 +814,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow v.startDragAndDrop( ClipData.newPlainText("", ""), new View.DragShadowBuilder(binding.buttonVisibility) { - public void onDrawShadow(@NonNull Canvas canvas) {} + public void onDrawShadow(@NonNull Canvas canvas) { + } }, null, View.DRAG_FLAG_GLOBAL); @@ -927,48 +952,46 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow startTime = SystemClock.uptimeMillis(); binding.mouseButtonsPosition.setPressed(true); break; - case MotionEvent.ACTION_MOVE: - { - int[] offset = new int[2]; - int[] offset2 = new int[2]; - binding.mouseButtons.getLocationOnScreen(offset); - binding.frame.getLocationOnScreen(offset2); - binding.mouseButtons.setX( - MathUtils.clamp( - offset[0] - startOffset[0] + e.getX(), - offset2[0], - offset2[0] - + binding.frame.getWidth() - - binding.mouseButtons.getWidth())); - binding.mouseButtons.setY( - MathUtils.clamp( - offset[1] - startOffset[1] + e.getY(), - offset2[1], - offset2[1] - + binding.frame.getHeight() - - binding.mouseButtons.getHeight())); - break; - } - case MotionEvent.ACTION_UP: - { - final int[] _pos = new int[2]; - binding.mouseButtons.getLocationOnScreen(_pos); - int deltaX = - (int) (startOffset[0] - e.getX()) - + (startPosition[0] - _pos[0]); - int deltaY = - (int) (startOffset[1] - e.getY()) - + (startPosition[1] - _pos[1]); - binding.mouseButtonsPosition.setPressed(false); + case MotionEvent.ACTION_MOVE: { + int[] offset = new int[2]; + int[] offset2 = new int[2]; + binding.mouseButtons.getLocationOnScreen(offset); + binding.frame.getLocationOnScreen(offset2); + binding.mouseButtons.setX( + MathUtils.clamp( + offset[0] - startOffset[0] + e.getX(), + offset2[0], + offset2[0] + + binding.frame.getWidth() + - binding.mouseButtons.getWidth())); + binding.mouseButtons.setY( + MathUtils.clamp( + offset[1] - startOffset[1] + e.getY(), + offset2[1], + offset2[1] + + binding.frame.getHeight() + - binding.mouseButtons.getHeight())); + break; + } + case MotionEvent.ACTION_UP: { + final int[] _pos = new int[2]; + binding.mouseButtons.getLocationOnScreen(_pos); + int deltaX = + (int) (startOffset[0] - e.getX()) + + (startPosition[0] - _pos[0]); + int deltaY = + (int) (startOffset[1] - e.getY()) + + (startPosition[1] - _pos[1]); + binding.mouseButtonsPosition.setPressed(false); - if (deltaX * deltaX + deltaY * deltaY < touchSlop - && SystemClock.uptimeMillis() - startTime - <= tapTimeout) { - v.performClick(); - return true; - } - break; + if (deltaX * deltaX + deltaY * deltaY < touchSlop + && SystemClock.uptimeMillis() - startTime + <= tapTimeout) { + v.performClick(); + return true; } + break; + } } return true; } @@ -1067,8 +1090,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow binding.mouseButtons .setVisibility( p.getBoolean("showMouseHelper", false) - && "1".equals(p.getString("touchMode", "1")) - && mClientConnected + && "1".equals(p.getString("touchMode", "1")) + && mClientConnected ? View.VISIBLE : View.GONE); @@ -1146,11 +1169,11 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow 37.5f * getResources().getDisplayMetrics().density * (mExtraKeys.getExtraKeysInfo() == null - ? 0 - : mExtraKeys - .getExtraKeysInfo() - .getMatrix() - .length)); + ? 0 + : mExtraKeys + .getExtraKeysInfo() + .getMatrix() + .length)); terminalToolbarViewPager.setLayoutParams(layoutParams); } binding.frame.setPadding( @@ -1158,8 +1181,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow 0, 0, preferences.getBoolean("adjustHeightForEK", false) - && terminalToolbarViewPager.getVisibility() - == View.VISIBLE + && terminalToolbarViewPager.getVisibility() + == View.VISIBLE ? terminalToolbarViewPager.getHeight() : 0); }, @@ -1213,8 +1236,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow public boolean handleKey(KeyEvent e) { if (filterOutWinKey && (e.getKeyCode() == KEYCODE_META_LEFT - || e.getKeyCode() == KEYCODE_META_RIGHT - || e.isMetaPressed())) return false; + || e.getKeyCode() == KEYCODE_META_RIGHT + || e.isMetaPressed())) return false; return mLorieKeyListener.onKey(getLorieView(), e.getKeyCode(), e); } @@ -1319,15 +1342,15 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow if (appOpsManager == null) return false; else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return appOpsManager.unsafeCheckOpNoThrow( - AppOpsManager.OPSTR_PICTURE_IN_PICTURE, - android.os.Process.myUid(), - context.getPackageName()) + AppOpsManager.OPSTR_PICTURE_IN_PICTURE, + android.os.Process.myUid(), + context.getPackageName()) == AppOpsManager.MODE_ALLOWED; else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return appOpsManager.checkOpNoThrow( - AppOpsManager.OPSTR_PICTURE_IN_PICTURE, - android.os.Process.myUid(), - context.getPackageName()) + AppOpsManager.OPSTR_PICTURE_IN_PICTURE, + android.os.Process.myUid(), + context.getPackageName()) == AppOpsManager.MODE_ALLOWED; else return false; @@ -1384,8 +1407,8 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow binding.mouseButtons .setVisibility( p.getBoolean("showMouseHelper", false) - && "1".equals(p.getString("touchMode", "1")) - && mClientConnected + && "1".equals(p.getString("touchMode", "1")) + && mClientConnected ? View.VISIBLE : View.GONE); binding.stub @@ -1433,6 +1456,31 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow return mInputHandler.shouldInterceptKeys(); } + private void setupSound() { + if (streamAudio == null) { + streamAudio = new StreamAudio(X11Activity.this); + streamAudio.setFile(VmFileManager.findAudioRaw(X11Activity.this, Config.vmID)); + + if (VmAudioManager.currentVmId.equals(Config.vmID) && VmAudioManager.streamAudio.isPlaying()) + streamAudio.setCross(VmAudioManager.streamAudio); + + playSound(); + } + } + + int playSoundRequests; + + private void playSound() { + if (streamAudio == null || streamAudio.isPlaying() || playSoundRequests > 0) return; + playSoundRequests++; + + streamAudio.stop(); + new Handler(Looper.getMainLooper()).postDelayed(() -> { + if (!streamAudio.isPlaying()) streamAudio.play(); + playSoundRequests--; + }, 100); + } + private void shutdownthisvm() { QmpSender.quickShutdown(); Config.setDefault(); diff --git a/app/src/main/res/layout/activity_x11_display_settings.xml b/app/src/main/res/layout/activity_x11_display_settings.xml index 0acac86..9c08ef9 100644 --- a/app/src/main/res/layout/activity_x11_display_settings.xml +++ b/app/src/main/res/layout/activity_x11_display_settings.xml @@ -195,6 +195,25 @@ app:layout_constraintTop_toTopOf="parent" android:clickable="false"/> + + + + + + + + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index e0dc92d..6d5446f 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -750,6 +750,7 @@ Dùng ứng dụng Termux:X11 thay vì màn hình có sẵn. Hiệu ứng mờ Làm mờ xung quanh để tăng khả năng tập trung vào một vùng cần được chú ý. + Bạn cần khởi động lại ứng dụng khi chuyển đổi giữa tích hợp sẵn và ngoài. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a781a5..338eb8e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -603,6 +603,7 @@ In system settings. Missing packages These are the missing packages that you should install: + You need to restart the app when switching between built-in and external. diff --git a/js/push_notification.js b/js/push_notification.js index 2fe9bed..825cf17 100644 --- a/js/push_notification.js +++ b/js/push_notification.js @@ -11,8 +11,9 @@ async function sendNotification() { title: "Vectras VM", message: "Welcome!", image: "https://github.com/xoureldeen/Vectras-VM-Android/blob/master/resources/vectrasvm.png", - url : "https://github.com/xoureldeen/Vectras-VM-Android", - //targetVersions: "3.9.0,3.9.1" + url: "https://github.com/xoureldeen/Vectras-VM-Android", + //activityClass: "update", + //targetVersions: "4.1.0,4.2.0", targetVersions: "" }, topic: "vectrasvmandroidgithub" diff --git a/qemu/7.2.22/upgrade.sh b/qemu/7.2.22/upgrade.sh index 2bfcada..f4771b2 100644 --- a/qemu/7.2.22/upgrade.sh +++ b/qemu/7.2.22/upgrade.sh @@ -44,7 +44,7 @@ rm -rf /usr/share/qemu clear echo -e "\e[1;37m[i] Downloading..." -aria2c -x 4 --async-dns=false --disable-ipv6 --check-certificate=false -o setup.tar.gz https://archive.org/download/qemu-7-2-22-for-vectras-vm-nbab/base-vectras-vm-arm64-v8a.tar.gz +aria2c -x 4 --async-dns=false --disable-ipv6 --check-certificate=false -o setup.tar.gz https://archive.org/download/qemu-7-2-22-for-vectras-vm-nbab/base-june-2026-vectras-vm-arm64-v8a.tar.gz clear echo -e "\e[1;37m[i] Installing..." diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index d04897a..626adef 100644 --- a/web/data/UpdateConfig.json +++ b/web/data/UpdateConfig.json @@ -5,11 +5,11 @@ "url": "https://github.com/xoureldeen/Vectras-VM-Android/releases", "Message": "

4.1.0

\nBugs fixed.", "cancellable": true, - "versionCodeBeta":"127", - "versionNameBeta":"4.2.3", - "versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.0,4.2.1,4.2.2,4.2.3", + "versionCodeBeta":"128", + "versionNameBeta":"4.2.4", + "versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.0,4.2.1,4.2.2,4.2.3,4.2.4", "sizeBeta": "45 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

4.2.3

Bugs fixed.", + "MessageBeta": "

4.2.4

Bugs fixed.", "cancellableBeta": true }