- Added settings for X11 display.
- Added option to run Qemu with Xterm.
- Fixed missing fluxbox.
- Improved X11 on Android 14+.
- Improved System monitor stability.
- Improved interface for Quick Edit.
- Added option to check rom file before extracting.
- Improved interface for Theme settings.
This commit is contained in:
An Bui 2025-12-09 00:24:45 +07:00
parent 1e085bb8d6
commit 6130045432
28 changed files with 802 additions and 406 deletions

1
.gitignore vendored
View file

@ -49,6 +49,7 @@ captures/
#.idea/modules.xml
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
#.idea/navEditor.xml
.kotlin/
# Keystore files
# Uncomment the following lines if you do not want to check your keystore files in.

View file

@ -13,8 +13,8 @@ android {
applicationId "com.vectras.vm"
minSdk minApi
targetSdk targetApi
versionCode 45
versionName "3.4.1"
versionCode 46
versionName "3.4.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
@ -110,6 +110,7 @@ dependencies {
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation "androidx.documentfile:documentfile:1.1.0"
implementation 'androidx.core:core-ktx:1.17.0'
implementation 'androidx.activity:activity:1.12.1'
compileOnly project(':shell-loader:stub')
implementation project(":terminal-view")
implementation project(":library")

View file

@ -48,6 +48,10 @@
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".settings.X11DisplaySettingsActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:exported="false" />
<activity
android:name=".setupwizard.SetupWizard2Activity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"

View file

@ -490,117 +490,117 @@ public class MainSettingsManager extends AppCompatActivity
}
public static boolean getVncExternal(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getVncExternal(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("vncExternal", false);
}
public static void setVncExternal(Activity activity, boolean vncExternal) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setVncExternal(Context context, boolean vncExternal) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("vncExternal", vncExternal);
edit.apply();
}
public static String getVncExternalDisplay(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getVncExternalDisplay(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("vncExternalDisplay", "1");
}
public static void setVncExternalDisplay(Activity activity, String vncExternalDisplay) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setVncExternalDisplay(Context context, String vncExternalDisplay) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("vncExternalDisplay", vncExternalDisplay);
edit.apply();
}
public static String getVncExternalPassword(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getVncExternalPassword(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("vncExternalPassword", "");
}
public static void setVncExternalPassword(Activity activity, String vncExternalPassword) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setVncExternalPassword(Context context, String vncExternalPassword) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("vncExternalPassword", vncExternalPassword);
edit.apply();
}
public static int getOrientationSetting(Activity activity) {
public static int getOrientationSetting(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// UIUtils.log("Getting First time: " + firstTime);
return prefs.getInt("orientation", 0);
}
public static void setOrientationSetting(Activity activity, int orientation) {
public static void setOrientationSetting(Context context, int orientation) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("orientation", orientation);
edit.apply();
}
static boolean getPrio(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
static boolean getPrio(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("HighPrio", false);
}
public static void setPrio(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setPrio(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("HighPrio", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getAlwaysShowMenuToolbar(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getAlwaysShowMenuToolbar(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("AlwaysShowMenuToolbar", false);
}
public static void setAlwaysShowMenuToolbar(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setAlwaysShowMenuToolbar(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("AlwaysShowMenuToolbar", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getFullscreen(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getFullscreen(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("ShowFullscreen", true);
}
public static void setFullscreen(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setFullscreen(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("ShowFullscreen", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getDesktopMode(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getDesktopMode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("DesktopMode", false);
}
public static void setDesktopMode(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setDesktopMode(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("DesktopMode", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getEnableLegacyFileManager(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getEnableLegacyFileManager(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("EnableLegacyFileManager", false);
}
public static void setEnableLegacyFileManager(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setEnableLegacyFileManager(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("EnableLegacyFileManager", flag);
edit.apply();
@ -696,175 +696,175 @@ public class MainSettingsManager extends AppCompatActivity
return prefs.getBoolean("modeNight", false);
}
public static void setCusRam(Activity activity, Boolean cusRam) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setCusRam(Context context, Boolean cusRam) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("customMemory", cusRam);
edit.apply();
}
public static boolean getCusRam(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getCusRam(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("customMemory", false);
}
public static boolean autoCreateDisk(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean autoCreateDisk(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("autoCreateDisk", false);
}
public static boolean useDefaultBios(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean useDefaultBios(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("useDefaultBios", true);
}
public static boolean useMemoryOvercommit(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean useMemoryOvercommit(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("useMemoryOvercommit", true);
}
public static boolean useLocalTime(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean useLocalTime(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("useLocalTime", true);
}
public static boolean copyFile(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean copyFile(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("copyFile", true);
}
public static void setIfType(Activity activity, String type) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setIfType(Context context, String type) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("ifType", type);
edit.apply();
}
public static String getIfType(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getIfType(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("ifType", "");
}
public static void setBoot(Activity activity, String boot) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setBoot(Context context, String boot) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("boot", boot);
edit.apply();
}
public static String getBoot(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getBoot(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("boot", "c");
}
public static void setVmUi(Activity activity, String vmUi) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setVmUi(Context context, String vmUi) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("vmUi", vmUi);
edit.apply();
}
public static String getVmUi(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getVmUi(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("vmUi", "X11");
}
public static void setResolution(Activity activity, String RESOLUTION) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setResolution(Context context, String RESOLUTION) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("RESOLUTION", RESOLUTION);
edit.apply();
}
public static String getResolution(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getResolution(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("RESOLUTION", "800x600x32");
}
public static void setSoundCard(Activity activity, String soundCard) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setSoundCard(Context context, String soundCard) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("soundCard", soundCard);
edit.apply();
}
public static String getSoundCard(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getSoundCard(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("soundCard", "None");
}
public static void setUsbTablet(Activity activity, boolean UsbTablet) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setUsbTablet(Context context, boolean UsbTablet) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("UsbTablet", UsbTablet);
edit.apply();
}
public static boolean getUsbTablet(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getUsbTablet(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("UsbTablet", false);
}
public static void setSharedFolder(Activity activity, boolean enable) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setSharedFolder(Context context, boolean enable) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("sharedFolder", enable);
edit.apply();
}
public static boolean getSharedFolder(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getSharedFolder(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("sharedFolder", false);
}
public static void setArch(Activity activity, String vmArch) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setArch(Context context, String vmArch) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("vmArch", vmArch);
edit.apply();
}
public static String getArch(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getArch(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("vmArch", "X86_64");
}
public static void setLang(Activity activity, String language) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setLang(Context context, String language) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("language", language);
edit.apply();
}
public static String getLang(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static String getLang(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("language", "en");
}
public static boolean isFirstLaunch(Activity activity) {
public static boolean isFirstLaunch(Context context) {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(Objects.requireNonNull(activity.getClass().getPackage()).getName(),
pInfo = context.getPackageManager().getPackageInfo(Objects.requireNonNull(context.getClass().getPackage()).getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "isFirstLaunch", e);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
assert pInfo != null;
return prefs.getBoolean("firstTime" + pInfo.versionName, true);
}
public static void setFirstLaunch(Activity activity) {
public static void setFirstLaunch(Context context) {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(Objects.requireNonNull(activity.getClass().getPackage()).getName(),
pInfo = context.getPackageManager().getPackageInfo(Objects.requireNonNull(context.getClass().getPackage()).getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "setFirstLaunch", e);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
assert pInfo != null;
edit.putBoolean("firstTime" + pInfo.versionName, false);
@ -872,28 +872,28 @@ public class MainSettingsManager extends AppCompatActivity
}
public static boolean getPromptUpdateVersion(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getPromptUpdateVersion(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("updateVersionPrompt", Config.defaultCheckNewVersion);
}
public static void setPromptUpdateVersion(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setPromptUpdateVersion(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("updateVersionPrompt", flag);
edit.apply();
// UIUtils.log("Setting First time: ");
}
public static boolean getcheckforupdatesfromthebetachannel(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static boolean getcheckforupdatesfromthebetachannel(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("checkforupdatesfromthebetachannel", false);
}
public static void setcheckforupdatesfromthebetachannel(Activity activity, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
public static void setcheckforupdatesfromthebetachannel(Context context, boolean flag) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("checkforupdatesfromthebetachannel", flag);
edit.apply();
@ -1079,4 +1079,28 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("cyclicRedundancyCheck", true);
}
public static void setCheckBeforeExtract(Context context, Boolean _boolean) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("checkBeforeExtract", _boolean);
edit.apply();
}
public static Boolean getCheckBeforeExtract(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("checkBeforeExtract", true);
}
public static void setRunQemuWithXterm(Context context, Boolean _boolean) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("runQemuWithXterm", _boolean);
edit.apply();
}
public static Boolean getRunQemuWithXterm(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("runQemuWithXterm", true);
}
}

View file

@ -75,13 +75,13 @@ public class AppConfig {
public static String pendingCommand = "";
public static String neededPkgs = "bash aria2 tar dwm xfce4-terminal xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
" libusbredirparser usbredir-dev libiscsi-dev sdl2 sdl2-dev sdl2_image-dev libepoxy-dev virglrenderer-dev rdma-core" +
" libusbredirparser usbredir-dev libiscsi-dev sdl2 sdl2-dev sdl2_image-dev libepoxy-dev virglrenderer-dev rdma-core fluxbox" +
" libusb libaio ncurses-libs curl libnfs gtk+3.0 gtk+3.0-dev fuse libpulse libseccomp jack pipewire liburing pulseaudio pulseaudio-alsa alsa-plugins-pulse" +
" mesa-dri-gallium mesa-vulkan-swrast vulkan-loader mesa-utils mesa-egl mesa-gbm mesa-vulkan-ati mesa-vulkan-broadcom mesa-vulkan-freedreno mesa-vulkan-panfrost qemu-audio-sdl";
public static String neededPkgs32bit = "bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
" libusbredirparser usbredir-dev libiscsi-dev sdl2 sdl2-dev libepoxy-dev virglrenderer-dev rdma-core pulseaudio pulseaudio-alsa alsa-plugins-pulse" +
" libusb ncurses-libs curl libnfs gtk+3.0 fuse libpulse libseccomp jack pipewire liburing tigervnc qemu-audio-sdl";
" libusb ncurses-libs curl libnfs gtk+3.0 fuse libpulse libseccomp jack pipewire liburing tigervnc qemu-audio-sdl fluxbox";
public static boolean needreinstallsystem = false;

View file

@ -28,7 +28,6 @@ public class MainService extends Service {
public static String env = null;
private String TAG = "MainService";
public static MainService service;
public static Activity activity;
@Override
public void onCreate() {
@ -50,11 +49,11 @@ public class MainService extends Service {
if (env != null) {
if (service != null) {
Terminal vterm = new Terminal(activity);
Terminal vterm = new Terminal(this);
if (Build.VERSION.SDK_INT < 34) {
vterm.executeShellCommand2("dwm", false, activity);
vterm.executeShellCommand2("dwm", false, this);
}
vterm.executeShellCommand2(env, true, activity);
vterm.executeShellCommand2(env, true, this);
}
} else
Log.e(TAG, "env is null");
@ -70,7 +69,7 @@ public class MainService extends Service {
//TODO: Not Work
//Terminal.killQemuProcess();
VMManager.killallqemuprocesses(activity);
VMManager.killallqemuprocesses(VectrasApp.getContext());
}
});
@ -110,11 +109,11 @@ public class MainService extends Service {
}
}
public static void startCommand(String _env, Activity _activity) {
Terminal vterm = new Terminal(_activity);
public static void startCommand(String _env, Context _context) {
Terminal vterm = new Terminal(_context);
if (Build.VERSION.SDK_INT < 34) {
vterm.executeShellCommand2("dwm", false, _activity);
vterm.executeShellCommand2("dwm", false, _context);
}
vterm.executeShellCommand2(_env, true, _activity);
vterm.executeShellCommand2(_env, true, _context);
}
}

View file

@ -22,12 +22,16 @@ public class QemuParamsEditorActivity extends AppCompatActivity {
binding = ActivityQemuParamsEditorBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main));
binding.appbar.post(() -> binding.appbar.setExpanded(false, false));
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(v -> finish());
if (getIntent().hasExtra("content")) {
result = getIntent().getStringExtra("content");
binding.edittext1.setText(result);
}
binding.materialbutton1.setOnClickListener(v -> {
binding.done.setOnClickListener(v -> {
result = binding.edittext1.getText().toString();
finish();
});

View file

@ -35,6 +35,7 @@ import com.vectras.qemu.MainVNCActivity;
import com.vectras.qemu.VNCConfig;
import com.vectras.qemu.utils.QmpClient;
import com.vectras.vm.home.HomeActivity;
import com.vectras.vm.home.core.HomeStartVM;
import com.vectras.vm.settings.VNCSettingsActivity;
import com.vectras.vm.utils.DialogUtils;
import com.vectras.vm.utils.FileUtils;
@ -49,11 +50,13 @@ import org.json.JSONArray;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.Random;
import java.util.Vector;
public class VMManager {
@ -70,6 +73,7 @@ public class VMManager {
public static int restoredVMs = 0;
public static boolean isKeptSomeFiles = false;
public static boolean isQemuStopedWithError = false;
public static boolean isTryAgain = false;
public static String latestUnsafeCommandReason = "";
public static String lastQemuCommand = "";
@ -583,7 +587,7 @@ public class VMManager {
}
}
public static boolean isExecutedCommandError(@NonNull String _command, String _result, Activity _activity) {
public static boolean isExecutedCommandError(@NonNull String _command, String _result, Context _activity) {
if (!_command.contains("qemu-system")) {
isQemuStopedWithError = false;
return false;
@ -604,41 +608,51 @@ public class VMManager {
Intent intent = new Intent();
intent.setClass(_activity, SplashActivity.class);
_activity.startActivity(intent);
_activity.finish();
},
null, null);
isQemuStopedWithError = true;
return true;
} else if (_result.contains(") exists") && _result.contains("drive with bus")) {
//Error code: DRIVE_INDEX_0_EXISTS
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_DRIVE_INDEX_0_EXISTS) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.hard_drive_24px, true,null, null);
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_DRIVE_INDEX_0_EXISTS) + "\n\n" + _result, R.drawable.hard_drive_24px);
isQemuStopedWithError = true;
return true;
} else if (_result.contains("gtk initialization failed") || _result.contains("x11 not available")) {
//Error code: X11_NOT_AVAILABLE
DialogUtils.twoDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_X11_NOT_AVAILABLE), _activity.getString(R.string.continuetext), _activity.getString(R.string.cancel), true, R.drawable.cast_24px, true,
DialogUtils.twoDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_X11_NOT_AVAILABLE), _activity.getString(R.string.switch_to_vnc), _activity.getString(R.string.cancel), true, R.drawable.cast_24px, true,
() -> {
MainSettingsManager.setVmUi(_activity, "VNC");
DialogUtils.oneDialog(_activity, _activity.getString(R.string.done), _activity.getString(R.string.switched_to_VNC), _activity.getString(R.string.ok),true, R.drawable.check_24px, true,null, null);
DialogUtils.oneDialog(_activity, _activity.getString(R.string.done), _activity.getString(R.string.switched_to_VNC), R.drawable.check_24px);
},
null, null);
isQemuStopedWithError = true;
return true;
} else if (_result.contains("Couldn't connect to XServer")) {
if (isTryAgain) {
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.x11_display_cannot_be_used_at_this_time_content) + "\n\n" + _result, R.drawable.cast_warning_24px);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
isTryAgain = false;
} else {
HomeStartVM.startTryAgain(_activity);
isTryAgain = true;
}
return true;
} else if (_result.contains("No such file or directory")) {
//Error code: NO_SUCH_FILE_OR_DIRECTORY
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_NO_SUCH_FILE_OR_DIRECTORY) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null);
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_NO_SUCH_FILE_OR_DIRECTORY) + "\n\n" + _result, R.drawable.file_copy_24px);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
} else if (_result.contains("another process using")) {
//Error code: ANOTHER_PROCESS_USING_IMAGE
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_ANOTHER_PROCESS_USING_IMAGE) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null);
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_ANOTHER_PROCESS_USING_IMAGE) + "\n\n" + _result, R.drawable.file_copy_24px);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
} else if (_command.contains("qemu-system") && _result.contains("qemu-system") && !_result.contains("warning:")) {
//Error code: UNKNOW_ERROR
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.vm_could_not_be_run_content) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.error_96px, true,null, null);
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.vm_could_not_be_run_content) + "\n\n" + _result, R.drawable.error_96px);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
@ -672,11 +686,12 @@ public class VMManager {
}
public static void fixRomsDataJsonResult(Activity _context) {
if (restoredVMs == 0) {
DialogUtils.oneDialog(_context, _context.getString(R.string.done), _context.getString(R.string.roms_data_json_fixed_unsuccessfully), _context.getString(R.string.ok),true, R.drawable.error_96px, true,null, null);
} else {
DialogUtils.oneDialog(_context, _context.getString(R.string.done), _context.getString(R.string.roms_data_json_fixed_successfully), _context.getString(R.string.ok),true, R.drawable.check_24px, true,null, null);
}
DialogUtils.oneDialog(
_context,
_context.getString(R.string.done),
restoredVMs == 0 ? _context.getString(R.string.roms_data_json_fixed_unsuccessfully) : _context.getString(R.string.roms_data_json_fixed_successfully),
R.drawable.error_96px
);
HomeActivity.refeshVMListNow();
movetoRecycleBin();
}
@ -743,8 +758,8 @@ public class VMManager {
return true;
}
public static boolean isVMRunning(Activity activity, String vmID) {
String result = Terminal.executeShellCommandWithResult("ps -e", activity);
public static boolean isVMRunning(Context context, String vmID) {
String result = Terminal.executeShellCommandWithResult("ps -e", context);
if (result.contains(Config.getCacheDir() + "/" + vmID + "/qmpsocket")) {
Log.d("VMManager.isThisVMRunning", "Yes");
return true;

View file

@ -272,12 +272,10 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
checkMissingLibraries(this);
setupDrawer();
DisplaySystem.startTermuxX11();
DialogUtils.joinTelegram(this);
NotificationUtils.clearAll(this);
if (MainSettingsManager.getPromptUpdateVersion(this))
updateApp();
}
@ -342,6 +340,8 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
if (binding.searchview.isShowing()) binding.searchview.hide();
bindingContent.bottomNavigation.setSelectedItemId(R.id.item_home);
}
new Handler(Looper.getMainLooper()).post(() -> DisplaySystem.startTermuxX11(this));
}
private final ActivityResultLauncher<String> isoPicker =

View file

@ -4,6 +4,7 @@ import static android.os.Build.VERSION.SDK_INT;
import static com.vectras.vm.utils.LibraryChecker.isPackageInstalled2;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
@ -27,12 +28,13 @@ import java.util.Set;
public class DisplaySystem {
private static final String TAG = "DisplaySystem";
private static boolean isTermuxClassLoaded = false;
public static void launch(Activity activity) {
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
activity.startActivity(new Intent(activity, MainVNCActivity.class));
} else if (MainSettingsManager.getVmUi(activity).equals("X11")) {
DisplaySystem.launchX11(activity, false);
public static void launch(Context context) {
if (MainSettingsManager.getVmUi(context).equals("VNC")) {
context.startActivity(new Intent(context, MainVNCActivity.class));
} else if (MainSettingsManager.getVmUi(context).equals("X11")) {
DisplaySystem.launchX11(context, false);
}
}
@ -44,21 +46,21 @@ public class DisplaySystem {
activity.startActivity(new Intent(activity, MainVNCActivity.class));
}
public static void launchX11(Activity activity, boolean isKill) {
public static void launchX11(Context context, boolean isKill) {
if (!DeviceUtils.is64bit()) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.x11_feature_not_supported),
activity.getString(R.string.cpu_not_support_64_xfce),
activity.getString(R.string.ok),
context,
context.getString(R.string.x11_feature_not_supported),
context.getString(R.string.cpu_not_support_64_xfce),
context.getString(R.string.ok),
true, R.drawable.error_96px,
true,
null,
null
);
} else {
if (SDK_INT >= 34 && !PackageUtils.isInstalled("com.termux.x11", activity)) {
DialogUtils.needInstallTermuxX11(activity);
if (SDK_INT >= 34 && !PackageUtils.isInstalled("com.termux.x11", context)) {
DialogUtils.needInstallTermuxX11(context);
return;
}
@ -66,7 +68,7 @@ public class DisplaySystem {
String necessaryPackage = "fluxbox";
// Check if XFCE4 is installed
isPackageInstalled2(activity, necessaryPackage, (output, errors) -> {
isPackageInstalled2(context, necessaryPackage, (output, errors) -> {
boolean isInstalled = false;
// Check if the package exists in the installed packages output
@ -82,50 +84,62 @@ public class DisplaySystem {
// If not installed, show a dialog to install it
if (!isInstalled) {
DialogUtils.twoDialog(
activity,
activity.getString(R.string.action_needed),
activity.getString(R.string.the_required_package_is_not_installed_content),
activity.getString(R.string.install),
activity.getString(R.string.cancel),
context,
context.getString(R.string.action_needed),
context.getString(R.string.the_required_package_is_not_installed_content),
context.getString(R.string.install),
context.getString(R.string.cancel),
true,
R.drawable.desktop_24px,
true,
() -> {
String installCommand = "apk add " + necessaryPackage;
new Terminal(activity).executeShellCommand(installCommand, true, true, activity.getString(R.string.just_a_moment), activity);
new Terminal(context).executeShellCommand(installCommand, true, true, context.getString(R.string.just_a_moment), context);
},
null,
null
);
} else {
if (SDK_INT >= 34) {
// activity.startActivity(new Intent(activity, XServerActivity.class));
Log.d(TAG, "launchX11: Opened: com.termux.x11.MainActivity.");
// activity.startActivity(new Intent(activity, XServerActivity.class));
Intent intent = new Intent();
intent.setClassName("com.termux.x11", "com.termux.x11.MainActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
activity.startActivity(intent);
context.startActivity(intent);
try {
TermuxX11.main(new String[]{":0"});
} catch (Exception e) {
Log.e(TAG, "TermuxX11.main: ", e);
}
} else {
activity.startActivity(new Intent(activity, X11Activity.class));
context.startActivity(new Intent(context, X11Activity.class));
}
if (isKill) {
new Terminal(context).executeShellCommand2("killall fluxbox && " + (SDK_INT >= 34 ? "export DISPLAY=:0 && sleep 5 && " : "") + "fluxbox > /dev/null", false, context);
}
if (isKill)
new Terminal(activity).executeShellCommand2("killall fluxbox", false, activity);
new Terminal(activity).executeShellCommand2(SDK_INT >= 34 ? "export DISPLAY=:0 && sleep 5 && fluxbox" : "fluxbox", false, activity);
}
});
}
}
public static void startTermuxX11() {
public static void startTermuxX11(Context context) {
if (isTermuxClassLoaded || !MainSettingsManager.getVmUi(context).equals("X11")) return;
isTermuxClassLoaded = true;
Log.d(TAG, "startTermuxX11...");
if (Build.VERSION.SDK_INT < 34) {
ShellExecutor shellExec = new ShellExecutor();
shellExec.exec(TermuxService.PREFIX_PATH + "/bin/termux-x11 :0");
} else {
if (PackageUtils.isInstalled("com.termux.x11", context)){
try {
TermuxX11.main(new String[]{":0"});
} catch (Exception e) {
Log.e(TAG, "TermuxX11.main: ", e);
}
}
}
}
}

View file

@ -2,7 +2,7 @@ package com.vectras.vm.home.core;
import static android.os.Build.VERSION.SDK_INT;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
@ -42,6 +42,11 @@ public class HomeStartVM {
public static boolean isStopNow = false;
public static final Handler handlerForLaunch = new Handler(Looper.getMainLooper());
public static Runnable tickForLaunch = null;
public static String lastVMName = "";
public static String lastEnv = "";
public static String lastVMID = "";
public static String lastThumbnailFile = "";
public static String pendingVMName = "";
public static String pendingEnv = "";
public static String pendingVMID = "";
@ -50,7 +55,7 @@ public class HomeStartVM {
public static String runCommandFormat = "export TMPDIR=/tmp && mkdir -p $TMPDIR/pulse && export XDG_RUNTIME_DIR=/tmp && chmod -R 775 $TMPDIR/pulse && pulseaudio --start --exit-idle-time=-1 > /dev/null 2>&1 && %s";
public static void startNow(
Activity activity,
Context context,
String vmName,
String env,
String vmID,
@ -62,20 +67,25 @@ public class HomeStartVM {
if (pendingVMID.isEmpty()) return;
pendingVMID = "";
} else {
if (MainSettingsManager.getVmUi(activity).equals("X11")) {
runCommandFormat = String.format(runCommandFormat, "xterm -e bash -c '%s'");
lastVMName = vmName;
lastEnv = env;
lastVMID = vmID;
lastThumbnailFile = thumbnailFile;
if (MainSettingsManager.getVmUi(context).equals("X11")) {
if (MainSettingsManager.getRunQemuWithXterm(context)) {
runCommandFormat = String.format(runCommandFormat, "xterm -e bash -c '%s'");
} else {
runCommandFormat = String.format(runCommandFormat, "bash -c '%s'");
}
if (SDK_INT < 34) {
pendingVMName = vmName;
pendingEnv = env;
pendingVMID = vmID;
pendingThumbnailFile = thumbnailFile;
DisplaySystem.launch(activity);
DisplaySystem.launch(context);
return;
} else {
if (!PackageUtils.isInstalled("com.termux.x11", activity)) {
DialogUtils.needInstallTermuxX11(activity);
return;
}
}
}
}
@ -94,29 +104,39 @@ public class HomeStartVM {
File romDir = new File(Config.getCacheDir() + "/" + finalvmID);
if (!romDir.exists()) {
if (!romDir.mkdirs()) {
DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.vm_cache_dir_failed_to_create_content), activity.getString(R.string.ok), true, R.drawable.warning_48px, true, null, null);
DialogUtils.oneDialog(
context,
context.getString(R.string.problem_has_been_detected),
context.getString(R.string.vm_cache_dir_failed_to_create_content),
R.drawable.warning_48px
);
return;
}
}
if (!VMManager.isthiscommandsafe(env, activity.getApplicationContext())) {
DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.harmful_command_was_detected) + " " + activity.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason, activity.getString(R.string.ok), true, R.drawable.verified_user_24px, true, null, null);
if (!VMManager.isthiscommandsafe(env, context.getApplicationContext())) {
DialogUtils.oneDialog(
context,
context.getString(R.string.problem_has_been_detected),
context.getString(R.string.harmful_command_was_detected) + " " + context.getResources().getString(R.string.reason) + ": " + VMManager.latestUnsafeCommandReason,
R.drawable.verified_user_24px
);
return;
}
if (MainSettingsManager.getSharedFolder(activity)
&& !MainSettingsManager.getArch(activity).equals("I386")
&& FileUtils.getFolderSize(FileUtils.getExternalFilesDirectory(activity).getPath() + "/SharedFolder") * Math.pow(10, -6) > 516) {
if (MainSettingsManager.getSharedFolder(context)
&& !MainSettingsManager.getArch(context).equals("I386")
&& FileUtils.getFolderSize(FileUtils.getExternalFilesDirectory(context).getPath() + "/SharedFolder") * Math.pow(10, -6) > 516) {
DialogUtils.twoDialog(
activity,
activity.getString(R.string.problem_has_been_detected),
activity.getString(R.string.shared_folder_is_too_large_content),
activity.getString(R.string.open_shared_folder),
activity.getString(R.string.close),
context,
context.getString(R.string.problem_has_been_detected),
context.getString(R.string.shared_folder_is_too_large_content),
context.getString(R.string.open_shared_folder),
context.getString(R.string.close),
true,
R.drawable.warning_48px,
true,
() -> FileUtils.openFolder(activity, FileUtils.getExternalFilesDirectory(activity).getPath() + "/SharedFolder"),
() -> FileUtils.openFolder(context, FileUtils.getExternalFilesDirectory(context).getPath() + "/SharedFolder"),
null,
null
);
@ -125,76 +145,83 @@ public class HomeStartVM {
VMManager.lastQemuCommand = env;
if (VMManager.isVMRunning(activity, finalvmID)) {
Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show();
if (MainSettingsManager.getVmUi(activity).equals("VNC"))
activity.startActivity(new Intent(activity, MainVNCActivity.class));
else if (MainSettingsManager.getVmUi(activity).equals("X11"))
DisplaySystem.launchX11(activity, false);
if (VMManager.isVMRunning(context, finalvmID)) {
Toast.makeText(context, "This VM is already running.", Toast.LENGTH_LONG).show();
if (MainSettingsManager.getVmUi(context).equals("VNC"))
context.startActivity(new Intent(context, MainVNCActivity.class));
else if (MainSettingsManager.getVmUi(context).equals("X11"))
DisplaySystem.launchX11(context, false);
return;
}
if (AppConfig.getSetupFiles().contains("arm") && !AppConfig.getSetupFiles().contains("arm64")) {
if (env.contains("tcg,thread=multi")) {
DialogUtils.twoDialog(activity, activity.getResources().getString(R.string.problem_has_been_detected), activity.getResources().getString(R.string.can_not_use_mttcg), activity.getString(R.string.ok), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true,
() -> startNow(activity, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), finalvmID, thumbnailFile), null, null);
DialogUtils.twoDialog(context, context.getResources().getString(R.string.problem_has_been_detected), context.getResources().getString(R.string.can_not_use_mttcg), context.getString(R.string.ok), context.getString(R.string.cancel), true, R.drawable.warning_48px, true,
() -> startNow(context, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), finalvmID, thumbnailFile), null, null);
return;
}
}
if (MainSettingsManager.getArch(activity).equals("ARM64") && MainSettingsManager.getIfType(activity).equals("ide") && skipIDEwithARM64DialogInStartVM) {
DialogUtils.twoDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.you_cannot_use_IDE_hard_drive_type_with_ARM64), activity.getString(R.string.continuetext), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true,
if (MainSettingsManager.getArch(context).equals("ARM64") && MainSettingsManager.getIfType(context).equals("ide") && skipIDEwithARM64DialogInStartVM) {
DialogUtils.twoDialog(context, context.getString(R.string.problem_has_been_detected), context.getString(R.string.you_cannot_use_IDE_hard_drive_type_with_ARM64), context.getString(R.string.continuetext), context.getString(R.string.cancel), true, R.drawable.warning_48px, true,
() -> {
skipIDEwithARM64DialogInStartVM = true;
startNow(activity, vmName, env, finalvmID, thumbnailFile);
startNow(context, vmName, env, finalvmID, thumbnailFile);
}, null, null);
return;
} else if (skipIDEwithARM64DialogInStartVM) {
skipIDEwithARM64DialogInStartVM = false;
}
if (MainSettingsManager.getSharedFolder(activity) && MainSettingsManager.getArch(activity).equals("I386")) {
Toast.makeText(activity, R.string.shared_folder_is_not_used_because_i386_does_not_support_it, Toast.LENGTH_LONG).show();
if (MainSettingsManager.getSharedFolder(context) && MainSettingsManager.getArch(context).equals("I386")) {
Toast.makeText(context, R.string.shared_folder_is_not_used_because_i386_does_not_support_it, Toast.LENGTH_LONG).show();
}
if (MainSettingsManager.getVncExternal(activity) &&
if (MainSettingsManager.getVncExternal(context) &&
NetworkUtils.isPortOpen("localhost", Config.defaultVNCPort + Config.defaultVNCPort, 500)) {
DialogUtils.twoDialog(activity, activity.getString(R.string.problem_has_been_detected),
activity.getString(R.string.the_vnc_server_port_you_set_is_currently_in_use_by_other),
activity.getString(R.string.go_to_settings),
activity.getString(R.string.close),
DialogUtils.twoDialog(context, context.getString(R.string.problem_has_been_detected),
context.getString(R.string.the_vnc_server_port_you_set_is_currently_in_use_by_other),
context.getString(R.string.go_to_settings),
context.getString(R.string.close),
true, R.drawable.warning_48px, true,
() -> activity.startActivity(new Intent(activity, ExternalVNCSettingsActivity.class)),
() -> context.startActivity(new Intent(context, ExternalVNCSettingsActivity.class)),
null,
null);
return;
}
showProgressDialog(activity, vmName, thumbnailFile);
showProgressDialog(context, vmName, thumbnailFile);
VMManager.isQemuStopedWithError = false;
String finalCommand = VMManager.addAudioDevSdl(String.format(runCommandFormat, env));
if (MainSettingsManager.getVmUi(activity).equals("X11") && SDK_INT >= 34) {
finalCommand = "export DISPLAY=:0 && sleep 5\nfluxbox &\n" + finalCommand;
if (MainSettingsManager.getVmUi(context).equals("X11") && SDK_INT >= 34) {
finalCommand = "export DISPLAY=:0 && sleep 5\nfluxbox > /dev/null &\n" + finalCommand;
}
Log.i(TAG, finalCommand);
if (ServiceUtils.isServiceRunning(activity, MainService.class)) {
MainService.startCommand(finalCommand, activity);
if (ServiceUtils.isServiceRunning(context, MainService.class)) {
MainService.startCommand(finalCommand, context);
} else {
Intent serviceIntent = new Intent(activity, MainService.class);
Intent serviceIntent = new Intent(context, MainService.class);
MainService.env = finalCommand;
MainService.CHANNEL_ID = vmName;
MainService.activity = activity;
if (SDK_INT >= Build.VERSION_CODES.O) {
activity.startForegroundService(serviceIntent);
context.startForegroundService(serviceIntent);
} else {
activity.startService(serviceIntent);
context.startService(serviceIntent);
}
}
if (MainSettingsManager.getVmUi(context).equals("X11") && SDK_INT >= 34) {
if (!PackageUtils.isInstalled("com.termux.x11", context)) {
DialogUtils.needInstallTermuxX11(context);
return;
}
DisplaySystem.launchX11(context, false);
}
tickForLaunch = new Runnable() {
@Override
public void run() {
@ -204,21 +231,29 @@ public class HomeStartVM {
progressDialog.dismiss();
if (!isStopNow && !VMManager.isQemuStopedWithError) {
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
if (MainSettingsManager.getVncExternal(activity)) {
if (MainSettingsManager.getVmUi(context).equals("VNC")) {
if (MainSettingsManager.getVncExternal(context)) {
Config.currentVNCServervmID = finalvmID;
DialogUtils.oneDialog(activity, activity.getString(R.string.vnc_server), activity.getString(R.string.running_vm_with_vnc_server_content) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(activity)) + 5900) + ".", activity.getString(R.string.ok), true, R.drawable.cast_24px, true, null, null);
DialogUtils.oneDialog(context,
context.getString(R.string.vnc_server),
context.getString(R.string.running_vm_with_vnc_server_content) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(context)) + 5900) + ".",
R.drawable.cast_24px
);
} else {
MainVNCActivity.started = true;
activity.startActivity(new Intent(activity, MainVNCActivity.class));
context.startActivity(new Intent(context, MainVNCActivity.class));
}
// } else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) {
// //This feature is not available yet.
} else if (MainSettingsManager.getVmUi(activity).equals("X11") && SDK_INT >= 34) {
DisplaySystem.launchX11(activity, false);
}
Log.i(TAG, "Virtual machine running.");
} if (MainSettingsManager.getVmUi(context).equals("X11") && SDK_INT >= 34) {
Intent intent = new Intent();
intent.setClassName("com.termux.x11", "com.termux.x11.MainActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
context.startActivity(intent);
}
skipIDEwithARM64DialogInStartVM = false;
@ -242,14 +277,19 @@ public class HomeStartVM {
setDefault();
}
public static void startPending(Activity activity) {
public static void startTryAgain(Context context) {
startNow(context, lastVMName, lastEnv, lastVMID, lastThumbnailFile);
VMManager.isTryAgain = false;
}
public static void startPending(Context context) {
isLaunchFromPending = true;
startNow(activity, pendingVMName, pendingEnv, pendingVMID, pendingThumbnailFile);
startNow(context, pendingVMName, pendingEnv, pendingVMID, pendingThumbnailFile);
setDefault();
}
public static void showProgressDialog(Activity activity, String _content, String thumbnailFile) {
View progressView = LayoutInflater.from(activity).inflate(R.layout.dialog_start_vm, null);
public static void showProgressDialog(Context context, String _content, String thumbnailFile) {
View progressView = LayoutInflater.from(context).inflate(R.layout.dialog_start_vm, null);
TextView tvVMName = progressView.findViewById(R.id.vm_name);
tvVMName.setText(_content);
@ -260,7 +300,7 @@ public class HomeStartVM {
VMManager.setIconWithName(ivThumbnail, _content);
} else {
if (FileUtils.isFileExists(thumbnailFile)) {
Glide.with(activity.getApplicationContext())
Glide.with(context.getApplicationContext())
.load(new File(thumbnailFile))
.placeholder(R.drawable.ic_computer_180dp_with_padding)
.error(R.drawable.ic_computer_180dp_with_padding)
@ -277,7 +317,7 @@ public class HomeStartVM {
VMManager.shutdownCurrentVM();
});
progressDialog = new MaterialAlertDialogBuilder(activity, R.style.CenteredDialogTheme)
progressDialog = new MaterialAlertDialogBuilder(context, R.style.CenteredDialogTheme)
.setView(progressView)
.setCancelable(false)
.create();

View file

@ -41,6 +41,7 @@ public class SystemMonitorFragment extends Fragment {
final String TAG = "SystemMonitorFragment";
FragmentHomeSystemMonitorBinding binding;
ExecutorService executor = Executors.newSingleThreadExecutor();
ScheduledExecutorService executorUpdate;
boolean isStopUpdateMonitor = false;
@Override
@ -83,10 +84,18 @@ public class SystemMonitorFragment extends Fragment {
stopMonitor();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (executorUpdate != null && !executorUpdate.isShutdown()) {
executorUpdate.shutdownNow();
}
}
private void initialize() {
binding.btStopqemu.setOnClickListener(v -> VMManager.requestKillAllQemuProcess(requireActivity(), () -> {
ScheduledExecutorService executorUpdate = Executors.newSingleThreadScheduledExecutor();
executorUpdate = Executors.newSingleThreadScheduledExecutor();
executorUpdate.schedule(() -> {
if (getContext() != null) {
requireActivity().runOnUiThread(this::getQemuInfo);
@ -129,7 +138,7 @@ public class SystemMonitorFragment extends Fragment {
private final Runnable monitorTask = new Runnable() {
@Override
public void run() {
if (isStopUpdateMonitor) return;
if (isStopUpdateMonitor || !isAdded()) return;
updateSystemMonitor();
handler.postDelayed(this, 1000);
}
@ -147,6 +156,8 @@ public class SystemMonitorFragment extends Fragment {
@SuppressLint("SetTextI18n")
private void updateSystemMonitor() {
if (!isAdded()) return;
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
ActivityManager activityManager = (ActivityManager) requireActivity().getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
@ -187,6 +198,8 @@ public class SystemMonitorFragment extends Fragment {
@SuppressLint("SetTextI18n")
private void getQemuInfo() {
if (!isAdded()) return;
String currentArch = MainSettingsManager.getArch(requireActivity());
binding.tvQemuarch.setText(getString(R.string.arch) + " " + currentArch + ".");

View file

@ -4,13 +4,8 @@ import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.R;
import com.vectras.vm.databinding.ActivityExternalVncSettingsBinding;
import com.vectras.vm.databinding.ActivityImportExportSettingsBinding;
import java.util.Objects;
@ -33,11 +28,15 @@ public class ImportExportSettingsActivity extends AppCompatActivity {
private void initialize() {
binding.swSmartSizeCalculation.setChecked(MainSettingsManager.getSmartSizeCalculation(this));
binding.swCheckBeforeExtract.setChecked(MainSettingsManager.getCheckBeforeExtract(this));
binding.swCyclicRedundancyCheck.setChecked(MainSettingsManager.getCyclicRedundancyCheck(this));
binding.swSmartSizeCalculation.setOnCheckedChangeListener((buttonView, isChecked) -> MainSettingsManager.setSmartSizeCalculation(this, isChecked));
binding.lnSmartSizeCalculation.setOnClickListener(v -> binding.swSmartSizeCalculation.toggle());
binding.swCheckBeforeExtract.setOnCheckedChangeListener((buttonView, isChecked) -> MainSettingsManager.setCheckBeforeExtract(this, isChecked));
binding.lnCheckBeforeExtract.setOnClickListener(v -> binding.swCheckBeforeExtract.toggle());
binding.swCyclicRedundancyCheck.setOnCheckedChangeListener((buttonView, isChecked) -> MainSettingsManager.setCyclicRedundancyCheck(this, isChecked));
binding.lnCyclicRedundancyCheck.setOnClickListener(v -> binding.swCyclicRedundancyCheck.toggle());
}

View file

@ -0,0 +1,54 @@
package com.vectras.vm.settings;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.R;
import com.vectras.vm.databinding.ActivityX11DisplaySettingsBinding;
import java.util.Objects;
public class X11DisplaySettingsActivity extends AppCompatActivity {
ActivityX11DisplaySettingsBinding binding;
boolean isInitialized = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_external_vnc_settings);
binding = ActivityX11DisplaySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
binding.toolbar.setNavigationOnClickListener(view -> finish());
initialize();
}
private void initialize() {
binding.swEnabled.setChecked(MainSettingsManager.getVmUi(this).equals("X11"));
binding.swRunQemuWithXterm.setChecked(MainSettingsManager.getRunQemuWithXterm(this));
binding.swEnabled.setOnCheckedChangeListener((buttonView, isChecked) -> {
MainSettingsManager.setVmUi(this, isChecked ? "X11" : "VNC");
uiController(isChecked);
});
binding.lnEnabled.setOnClickListener(v -> binding.swEnabled.toggle());
binding.swRunQemuWithXterm.setOnCheckedChangeListener((buttonView, isChecked) -> MainSettingsManager.setRunQemuWithXterm(this, isChecked));
binding.lnRunQemuWithXtermh.setOnClickListener(v -> binding.swRunQemuWithXterm.toggle());
isInitialized = true;
uiController(binding.swEnabled.isChecked());
}
private void uiController(boolean isEnabled) {
binding.lnAllOptions.setAlpha(isEnabled ? 1f : 0.5f);
binding.lnRunQemuWithXtermh.setEnabled(isEnabled);
}
}

View file

@ -2,8 +2,8 @@ package com.vectras.vm.utils;
import static android.content.Intent.ACTION_VIEW;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
@ -26,10 +26,14 @@ import com.vectras.vm.R;
public class DialogUtils {
public static void oneDialog(Activity _context, String _title, String _message, String _textPositiveButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(_context).inflate(R.layout.dialog_layout, null);
public static void oneDialog(Context context, String title, String message, int iconid) {
oneDialog(context, title, message, context.getString(R.string.ok), iconid != -1, iconid, true, null, null);
}
AlertDialog dialog = new AlertDialog.Builder(_context).create();
public static void oneDialog(Context context, String _title, String _message, String _textPositiveButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
AlertDialog dialog = new AlertDialog.Builder(context).create();
dialog.setCancelable(_cancel);
dialog.setView(buttonsView);
@ -84,10 +88,10 @@ public class DialogUtils {
dialog.show();
}
public static void twoDialog(Activity _context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(_context).inflate(R.layout.dialog_layout, null);
public static void twoDialog(Context context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
AlertDialog dialog = new AlertDialog.Builder(_context).create();
AlertDialog dialog = new AlertDialog.Builder(context).create();
dialog.setCancelable(_cancel);
dialog.setView(buttonsView);
@ -151,10 +155,10 @@ public class DialogUtils {
dialog.show();
}
public static void threeDialog(Activity _context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, String _textNeutralButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onNeutral, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(_context).inflate(R.layout.dialog_layout, null);
public static void threeDialog(Context context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, String _textNeutralButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onNeutral, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
AlertDialog dialog = new AlertDialog.Builder(_context).create();
AlertDialog dialog = new AlertDialog.Builder(context).create();
dialog.setCancelable(_cancel);
dialog.setView(buttonsView);
@ -228,18 +232,18 @@ public class DialogUtils {
dialog.show();
}
public static void joinTelegram(Activity _activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(_activity);
public static void joinTelegram(Context _context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(_context);
if (!prefs.getBoolean("tgDialog", false)) {
threeDialog(_activity, _activity.getResources().getString(R.string.join_us_on_telegram),
_activity.getResources().getString(R.string.join_us_on_telegram_where_we_publish_all_the_news_and_updates_and_receive_your_opinions_and_bugs),
_activity.getResources().getString(R.string.join), _activity.getResources().getString(R.string.cancel), _activity.getResources().getString(R.string.dont_show_again),
threeDialog(_context, _context.getResources().getString(R.string.join_us_on_telegram),
_context.getResources().getString(R.string.join_us_on_telegram_where_we_publish_all_the_news_and_updates_and_receive_your_opinions_and_bugs),
_context.getResources().getString(R.string.join), _context.getResources().getString(R.string.cancel), _context.getResources().getString(R.string.dont_show_again),
true, R.drawable.send_24px, true,
() -> {
String tg = "https://t.me/vectras_os";
Intent f = new Intent(ACTION_VIEW);
f.setData(Uri.parse(tg));
_activity.startActivity(f);
_context.startActivity(f);
}, null,
() -> {
SharedPreferences.Editor edit = prefs.edit();
@ -249,26 +253,26 @@ public class DialogUtils {
}
}
public static void needInstallTermuxX11(Activity _activity) {
twoDialog(_activity, _activity.getResources().getString(R.string.action_needed),
_activity.getResources().getString(R.string.need_install_termux_x11_content),
_activity.getResources().getString(R.string.install), _activity.getResources().getString(R.string.cancel),
public static void needInstallTermuxX11(Context _context) {
twoDialog(_context, _context.getResources().getString(R.string.action_needed),
_context.getResources().getString(R.string.need_install_termux_x11_content),
_context.getResources().getString(R.string.install), _context.getResources().getString(R.string.cancel),
true, R.drawable.warning_24px, true,
() -> {
String tg = "https://github.com/termux/termux-x11/releases";
Intent f = new Intent(ACTION_VIEW);
f.setData(Uri.parse(tg));
_activity.startActivity(f);
_context.startActivity(f);
}, null, null);
}
public static void fileDeletionResult(Activity activity, boolean isCompleted) {
public static void fileDeletionResult(Context _context, boolean isCompleted) {
if (isCompleted) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.done),
activity.getString(R.string.file_deleted),
activity.getString(R.string.ok),
_context,
_context.getString(R.string.done),
_context.getString(R.string.file_deleted),
_context.getString(R.string.ok),
true,
R.drawable.check_24px,
true,
@ -277,10 +281,10 @@ public class DialogUtils {
);
} else {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.delete_file_failed_content),
activity.getString(R.string.ok),
_context,
_context.getString(R.string.oops),
_context.getString(R.string.delete_file_failed_content),
_context.getString(R.string.ok),
true,
R.drawable.error_96px,
true,

View file

@ -868,15 +868,15 @@ public class FileUtils {
return true;
}
public static void openFolder(Activity activity, String folderPath) {
public static void openFolder(Context context, String folderPath) {
File folder = new File(folderPath);
if (!folder.exists() || !folder.isDirectory()) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.directory_does_not_exist),
activity.getString(R.string.ok),
context,
context.getString(R.string.oops),
context.getString(R.string.directory_does_not_exist),
context.getString(R.string.ok),
true,
R.drawable.error_96px,
true,
@ -888,8 +888,8 @@ public class FileUtils {
}
Uri uri = FileProvider.getUriForFile(
activity,
activity.getPackageName() + ".provider",
context,
context.getPackageName() + ".provider",
folder
);
@ -900,13 +900,13 @@ public class FileUtils {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
activity.startActivity(intent);
context.startActivity(intent);
} catch (Exception e) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.there_is_no_app_to_perform_this_action),
activity.getString(R.string.ok),
context,
context.getString(R.string.oops),
context.getString(R.string.there_is_no_app_to_perform_this_action),
context.getString(R.string.ok),
true,
R.drawable.error_96px,
true,

View file

@ -89,11 +89,11 @@ public class LibraryChecker {
}
// Method to check if the package is installed
public static void isPackageInstalled2(Activity activity, String packageName, Terminal.CommandCallback callback) {
public static void isPackageInstalled2(Context context, String packageName, Terminal.CommandCallback callback) {
String command = "apk info";
Terminal terminal = new Terminal(activity);
terminal.executeShellCommand(command, activity, false, (output, errors) -> {
Terminal terminal = new Terminal(context);
terminal.executeShellCommand(command, context, false, (output, errors) -> {
if (callback != null) {
callback.onCommandCompleted(output, errors);
}

View file

@ -43,6 +43,11 @@ public class ZipUtils {
TextView statusTextView,
ProgressBar progressBar
) {
if (MainSettingsManager.getCheckBeforeExtract(context)) {
updateStatus(statusTextView, progressBar, context.getString(R.string.checking), 0);
if (isZipFileCorrupted(context, fileZip)) return false;
}
try {
File outdir = new File(destDir);
if (!outdir.exists()) outdir.mkdirs();
@ -213,6 +218,34 @@ public class ZipUtils {
}
}
public static boolean isZipFileCorrupted(Context context, String path) {
try (ZipFile zip = new ZipFile(path)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
byte[] buffer;
if (DeviceUtils.totalMemoryCapacity(context) < 4L * 1024 * 1024 * 1024)
buffer = new byte[64 * 1024];
else if (DeviceUtils.totalMemoryCapacity(context) < 11L * 1024 * 1024 * 1024)
buffer = new byte[128 * 1024];
else
buffer = new byte[256 * 1024];
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
try (InputStream is = zip.getInputStream(entry)) {
while (is.read(buffer) != -1) {
}
}
}
return false;
} catch (Exception e) {
return true;
}
}
public static boolean compress(
Context context,
String[] filePaths,

View file

@ -68,20 +68,20 @@ public class Terminal {
return null;
}
private void showDialog(String message, Activity activity, String usercommand) {
if (VMManager.isExecutedCommandError(usercommand, message, activity))
private void showDialog(String message, Context context, String usercommand) {
if (VMManager.isExecutedCommandError(usercommand, message, context))
return;
DialogUtils.twoDialog(activity, "Execution Result", message, activity.getString(R.string.copy), activity.getString(R.string.close), true, R.drawable.round_terminal_24, true,
() -> ClipboardUltils.copyToClipboard(activity, message), null, null);
DialogUtils.twoDialog(context, "Execution Result", message, context.getString(R.string.copy), context.getString(R.string.close), true, R.drawable.round_terminal_24, true,
() -> ClipboardUltils.copyToClipboard(context, message), null, null);
}
// Method to execute the shell command
public void executeShellCommand(String userCommand, boolean showResultDialog, boolean showProgressDialog, Activity dialogActivity) {
public void executeShellCommand(String userCommand, boolean showResultDialog, boolean showProgressDialog, Context dialogActivity) {
executeShellCommand(userCommand, showResultDialog, showProgressDialog, dialogActivity.getString(R.string.executing_command_please_wait), dialogActivity);
}
public void executeShellCommand(String userCommand, boolean showResultDialog, boolean showProgressDialog, String progressDialogMessage, Activity dialogActivity) {
public void executeShellCommand(String userCommand, boolean showResultDialog, boolean showProgressDialog, String progressDialogMessage, Context dialogActivity) {
StringBuilder output = new StringBuilder();
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
@ -147,7 +147,7 @@ public class Terminal {
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
// Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
}
@ -180,7 +180,7 @@ public class Terminal {
}).start();
}
public void executeShellCommand2(String userCommand, boolean showResultDialog, Activity dialogActivity) {
public void executeShellCommand2(String userCommand, boolean showResultDialog, Context dialogActivity) {
StringBuilder output = new StringBuilder();
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
@ -191,7 +191,7 @@ public class Terminal {
ProcessBuilder processBuilder = new ProcessBuilder();
// Adjust these environment variables as necessary for your app
String filesDir = context.getFilesDir().getAbsolutePath();
String filesDir = getContext().getFilesDir().getAbsolutePath();
File tmpDir = new File(context.getFilesDir(), "usr/tmp");
@ -245,7 +245,7 @@ public class Terminal {
// Read the input stream for the output of the command
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
// Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
}
@ -345,7 +345,7 @@ public class Terminal {
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
// Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
}
@ -474,7 +474,7 @@ public class Terminal {
void onCommandCompleted(String output, String errors);
}
public String executeShellCommand(String userCommand, Activity dialogActivity, boolean isShowProgressDialog, CommandCallback callback) {
public String executeShellCommand(String userCommand, Context dialogActivity, boolean isShowProgressDialog, CommandCallback callback) {
StringBuilder output = new StringBuilder();
StringBuilder errors = new StringBuilder();
Log.d(TAG, userCommand);
@ -541,7 +541,7 @@ public class Terminal {
String line;
while ((line = reader.readLine()) != null) {
Log.d(TAG, line);
// Log.d(TAG, line);
com.vectras.vm.logger.VectrasStatus.logError("<font color='#4db6ac'>VTERM: >" + line + "</font>");
output.append(line).append("\n");
}
@ -576,28 +576,6 @@ public class Terminal {
return "Execution is in progress..."; // Returning a message indicating the command execution is ongoing
}
private boolean checkInstallation() {
String filesDir = context.getFilesDir().getAbsolutePath();
File distro = new File(filesDir, "distro");
return distro.exists();
}
public static void killQemuProcess() {
if (qemuProcess != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
qemuProcess.destroyForcibly();
else
qemuProcess.destroy();
//MainVNCActivity.activity.finish();
MainVNCActivity.started = false;
qemuProcess = null; // Set it to null after destroying it
Log.d(TAG, "QEMU process destroyed.");
} else {
Log.d(TAG, "QEMU process was null.");
}
}
/**
* Checks if a package is installed using `apk info`.
*
@ -620,4 +598,11 @@ public class Terminal {
}
return false;
}
private Context getContext() {
if (context == null) {
return VectrasApp.getContext();
}
return context;
}
}

View file

@ -82,6 +82,48 @@
android:clickable="false"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ln_check_before_extract"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/object_shape_middle_high"
android:padding="16dp"
android:layout_marginBottom="2dp" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/sw_check_before_extract"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_before_extract"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/check_before_extract_note"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/sw_check_before_extract"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:clickable="false"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ln_cyclic_redundancy_check"
android:layout_width="match_parent"

View file

@ -1,47 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:id="@+id/main"
tools:context=".QemuParamsEditorActivity">
<LinearLayout
android:id="@+id/linear1"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Quick edit"
android:singleLine="true"
android:layout_weight="1"
android:textSize="18sp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/materialbutton1"
style="@style/Widget.Material3Expressive.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:gravity="center_horizontal|center_vertical"
android:text="Done" />
</LinearLayout>
<ScrollView
android:id="@+id/vscroll1"
android:gravity="center"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
style="@style/App.CollapsingToolbarLarge"
app:title="@string/quick_edit"
app:toolbarId="@id/toolbar" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_collapseMode="pin">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/App.CollapsingMaterialToolbar"
android:layout_width="0dp"
android:layout_weight="1"/>
<com.google.android.material.button.MaterialButton
style="?attr/materialIconButtonFilledStyle"
android:id="@+id/done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical"
app:icon="@drawable/check_24px"
app:iconSize="24dp"
app:iconGravity="textStart"/>
</LinearLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/edittext1"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:hint="Write something..."
android:background="@android:color/transparent"
android:textSize="12sp" />
</ScrollView>
</LinearLayout>
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/edittext1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/write_something"
android:background="@android:color/transparent" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -16,8 +16,7 @@
<com.google.android.material.appbar.CollapsingToolbarLayout
style="@style/App.CollapsingToolbarLarge"
app:title="@string/theme"
app:subtitle="@string/settings">
app:title="@string/theme">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
@ -35,76 +34,72 @@
android:id="@+id/ln_all_options"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:orientation="vertical"
android:animateLayoutChanges="true">
<com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Filled"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardBackgroundColor="?attr/colorCard">
<LinearLayout
android:layout_height="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:padding="16dp"
android:layout_marginBottom="2dp"
android:background="@drawable/object_shape_top_high">
<TextView
style="@style/TextAppearance.AppCompat.Title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:layout_margin="16dp">
android:layout_height="wrap_content"
android:text="@string/themes" />
<TextView
style="@style/TextAppearance.AppCompat.Title"
android:layout_width="match_parent"
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/dn_selector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/select_daynight"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/themes" />
android:layout_weight="1"
android:text="@string/system" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/dn_selector"
android:layout_width="match_parent"
<com.google.android.material.button.MaterialButton
android:id="@+id/select_day"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
app:selectionRequired="true"
app:singleSelection="true">
android:layout_weight="1"
android:text="@string/light" />
<com.google.android.material.button.MaterialButton
android:id="@+id/select_daynight"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/system" />
<com.google.android.material.button.MaterialButton
android:id="@+id/select_night"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dark" />
<com.google.android.material.button.MaterialButton
android:id="@+id/select_day"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/light" />
<com.google.android.material.button.MaterialButton
android:id="@+id/select_night"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dark" />
</com.google.android.material.button.MaterialButtonToggleGroup>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.button.MaterialButtonToggleGroup>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ln_dynamiccolor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:background="@drawable/object_shape_bottom_high"
android:padding="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/sw_dynamiccolor"

View file

@ -16,8 +16,7 @@
<com.google.android.material.appbar.CollapsingToolbarLayout
style="@style/App.CollapsingToolbarLarge"
app:title="@string/vnc"
app:subtitle="@string/settings">
app:title="@string/vnc">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"

View file

@ -0,0 +1,132 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context=".settings.X11DisplaySettingsActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
<com.google.android.material.appbar.CollapsingToolbarLayout
style="@style/App.CollapsingToolbarLarge"
app:title="@string/X11_display">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/App.CollapsingMaterialToolbar" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/ln_all_options"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="108dp"
android:paddingHorizontal="16dp"
android:paddingBottom="16dp"
android:orientation="vertical"
android:animateLayoutChanges="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ln_run_qemu_with_xtermh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/object_shape_single_high"
android:padding="16dp"
android:layout_marginBottom="2dp" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/sw_run_qemu_with_xterm"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/run_qemu_with_xterm"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/run_qemu_with_xterm_note"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/sw_run_qemu_with_xterm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:clickable="false"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<View
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="?attr/colorSurfaceContainerLow"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:backgroundTint="?attr/colorSecondaryContainer"
app:cardCornerRadius="50dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/ln_enabled"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingVertical="16dp"
android:paddingLeft="32dp"
android:paddingRight="20dp" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/use_X11_display"
android:textSize="16sp">
</TextView>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/sw_enabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/colorAccent"
android:clickable="false"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -3,7 +3,7 @@
<string name="app_name">Vectras VM</string>
<!--======================VECTRAS STRINGS====================-->
<string name="app_version" translatable="false">3.4.1</string>
<string name="app_version" translatable="false">3.4.2</string>
<string name="qemu_version" translatable="false">Stable</string>
<!-- logger -->
<string name="startvm">VM STARTED!</string>
@ -214,7 +214,7 @@
<string name="you_cannot_use_IDE_hard_drive_type_with_ARM64">You cannot use IDE hard drive type with ARM64. If you continue, the default hard drive type will be used.</string>
<string name="error_PROOT_IS_MISSING_0">The system is not working, necessary files are missing. This problem may be caused by incorrect setup. Do you want to try the setup again? Error code: PROOT_IS_MISSING_0.</string>
<string name="error_DRIVE_INDEX_0_EXISTS">An error occurred and the virtual machine cannot start. There are two or more drives that cannot be plugged into the same slot. Please check your virtual machine settings and make sure all drives are not plugged into the same slot. Error code: DRIVE_INDEX_0_EXISTS.</string>
<string name="error_X11_NOT_AVAILABLE">An error occurred and the virtual machine cannot start. X11 is not working. We recommend you switch to VNC. Do you want to switch to VNC? Error code: X11_NOT_AVAILABLE.</string>
<string name="error_X11_NOT_AVAILABLE">An error occurred and the virtual machine is not running. The X11 display is temporarily unavailable, please exit the Vectras VM and come back to try again. You can try switching to VNC which is more stable. Error code: X11_NOT_AVAILABLE.</string>
<string name="switched_to_VNC">Switched to VNC. You can try running the virtual machine again now.</string>
<string name="restore">Restore</string>
<string name="restore_content">Deleted virtual machines will be restored if you previously chose to keep all files.</string>
@ -459,6 +459,17 @@
<string name="the_required_package_is_not_installed_content">The required package is not installed, you need to install it before using this feature.</string>
<string name="need_install_termux_x11_content">Termux:X11 app is not installed, you need to install it to continue.</string>
<string name="X11_display">X11 display</string>
<string name="settings_for_X11_display">Settings for X11 display.</string>
<string name="use_X11_display">Use X11 display</string>
<string name="check_before_extract">Check before extract</string>
<string name="check_before_extract_note">Quickly detect errors to avoid wasting time decompressing and errors occurring after decompression.</string>
<string name="checking">Checking…</string>
<string name="x11_display_cannot_be_used_at_this_time_content">X11 display cannot be used at this time, try closing and reopening the Vectras VM.</string>
<string name="run_qemu_with_xterm">Run Qemu with Xterm</string>
<string name="run_qemu_with_xterm_note">To run commands with Qemu monitor easier without switching.</string>
<string name="quick_edit">Quick edit</string>
<string name="write_something">Write something…</string>
<string name="switch_to_vnc">Switch to VNC</string>
<!--======================TERMUX STRINGS====================-->

View file

@ -29,6 +29,15 @@
android:targetPackage="com.vectras.vm"
android:targetClass="com.vectras.vm.settings.VNCSettingsActivity" />
</Preference>
<Preference
android:key="x11display"
android:title="@string/X11_display"
android:summary="@string/settings_for_X11_display"
app:iconSpaceReserved="false">
<intent
android:targetPackage="com.vectras.vm"
android:targetClass="com.vectras.vm.settings.X11DisplaySettingsActivity" />
</Preference>
<Preference
android:key="x11"
android:fragment="com.vectras.vm.x11.LoriePreferences$LoriePreferenceFragment"

View file

@ -1,7 +1,7 @@
#Sun Nov 16 20:36:13 ICT 2025
#Mon Dec 08 19:38:26 ICT 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

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":"45",
"versionNameBeta":"3.4.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",
"versionCodeBeta":"46",
"versionNameBeta":"3.4.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",
"sizeBeta": "55 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>3.4.1</h2>Bugs fixed.",
"MessageBeta": "<h2>3.4.2</h2>Bugs fixed.",
"cancellableBeta": true
}