- Fixed no sound playing with Termux.
- Fixed invalid file path error when using Manual setup.
- Fixed dialog showing content without line breaks.
This commit is contained in:
An Bui 2025-11-19 17:36:28 +07:00
parent 2150380f01
commit debddf5a0c
11 changed files with 113 additions and 91 deletions

View file

@ -10,8 +10,8 @@ android {
applicationId "com.vectras.vm"
minSdk minApi
targetSdk targetApi
versionCode 35
versionName "3.3.1"
versionCode 36
versionName "3.3.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}

View file

@ -152,7 +152,7 @@ public final class BackgroundJob {
environment.add("LANG=en_US.UTF-8");
//environment.add("PATH=" + TermuxService.PREFIX_PATH + "/bin");
environment.add("PWD=" + cwd);
environment.add("TMPDIR=" + TermuxService.PREFIX_PATH + "/tmp");
environment.add("TMPDIR=/tmp");
environment.add("BOOTCLASSPATH=" + System.getenv("BOOTCLASSPATH"));
environment.add("ANDROID_ROOT=" + System.getenv("ANDROID_ROOT"));
environment.add("ANDROID_DATA=" + System.getenv("ANDROID_DATA"));

View file

@ -50,6 +50,15 @@ public class RomInfo extends AppCompatActivity {
private String currentViews = "0";
private boolean isAnBuiID = false;
private String contentID = "";
private String token = "";
private String urlToGetInfo = "";
private RequestNetwork net;
private RequestNetwork.RequestListener _net_request_listener;
private boolean retryUpdateView = true;
private boolean retrySendLike;
private boolean hasRetriedView;
private boolean hasRetriedLike;
private boolean waitingForUpdateLike;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -296,8 +305,8 @@ public class RomInfo extends AppCompatActivity {
binding.btnLike.setOnClickListener(v -> sendLikeUpdate(contentID));
if (!contentID.isEmpty()) {
RequestNetwork net = new RequestNetwork(this);
RequestNetwork.RequestListener _net_request_listener = new RequestNetwork.RequestListener() {
net = new RequestNetwork(this);
_net_request_listener = new RequestNetwork.RequestListener() {
@SuppressLint("SetTextI18n")
@Override
public void onResponse(String tag, String response, HashMap<String, Object> responseHeaders) {
@ -308,6 +317,8 @@ public class RomInfo extends AppCompatActivity {
}.getType()
);
if (map.containsKey("token")) token = Objects.requireNonNull(map.get("token")).toString();
binding.btnLike.setVisibility(View.VISIBLE);
String likeContent = getString(R.string.like);
boolean isLiked = MainSettingsManager.getLikes(RomInfo.this).contains("," + getIntent().getStringExtra("id"));
@ -336,6 +347,8 @@ public class RomInfo extends AppCompatActivity {
}
binding.tvViews.setText(viewsContent);
if (retryUpdateView) sendViewUpdate(contentID);
if (retrySendLike) sendLikeUpdate(contentID);
} else {
binding.lnAllViews.setVisibility(View.GONE);
binding.btnLike.setVisibility(View.GONE);
@ -351,7 +364,7 @@ public class RomInfo extends AppCompatActivity {
}
};
String urlToGetInfo = "https://go.anbui.ovh/egg/contentinfo?id=" + contentID + (isAnBuiID ? "" : "&app=vectrasvm");
urlToGetInfo = "https://go.anbui.ovh/egg/contentinfo?id=" + contentID + (isAnBuiID ? "" : "&app=vectrasvm");
net.startRequestNetwork(RequestNetworkController.GET,urlToGetInfo,"contentinfo", _net_request_listener);
Log.i(TAG, "urlToGetInfo: " + urlToGetInfo);
@ -360,6 +373,9 @@ public class RomInfo extends AppCompatActivity {
}
private void sendLikeUpdate(String id) {
if (waitingForUpdateLike) return;
waitingForUpdateLike = true;
String addlikecount;
if (MainSettingsManager.getLikes(this).contains("," + id)) {
@ -377,7 +393,8 @@ public class RomInfo extends AppCompatActivity {
String json = "{"
+ "\"id\":\"" + id + "\","
+ "\"addcount\":" + addlikecount
+ (isAnBuiID ? "" : ",\"app\":\"vectrasvm\"")
+ (isAnBuiID ? "" : ",\"app\":\"vectrasvm\",")
+ "\"token\":" + "\"" + token + "\""
+ "}";
RequestBody body = RequestBody.create(
@ -393,11 +410,26 @@ public class RomInfo extends AppCompatActivity {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
waitingForUpdateLike = false;
Log.e(TAG, "sendLikeUpdate: ", e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
int statusCode = response.code();
if (statusCode == 403 && !hasRetriedLike) {
retrySendLike = true;
hasRetriedLike = true;
waitingForUpdateLike = false;
net.startRequestNetwork(RequestNetworkController.GET, urlToGetInfo,"contentinfo", _net_request_listener);
return;
}
retrySendLike = false;
hasRetriedLike = false;
waitingForUpdateLike = false;
if (response.isSuccessful()) {
String resBody = response.body().string();
if (!resBody.isEmpty()) {
@ -433,7 +465,8 @@ public class RomInfo extends AppCompatActivity {
String json = "{"
+ "\"id\":\"" + id + "\""
+ (isAnBuiID ? "" : ",\"app\":\"vectrasvm\"")
+ (isAnBuiID ? "" : ",\"app\":\"vectrasvm\",")
+ "\"token\":" + "\"" + token + "\""
+ "}";
RequestBody body = RequestBody.create(
@ -454,6 +487,18 @@ public class RomInfo extends AppCompatActivity {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
int statusCode = response.code();
if (statusCode == 403 && !hasRetriedView) {
retryUpdateView = true;
hasRetriedView = true;
net.startRequestNetwork(RequestNetworkController.GET, urlToGetInfo,"contentinfo", _net_request_listener);
return;
}
retryUpdateView = false;
hasRetriedView = false;
if (response.isSuccessful()) {
String resBody = response.body().string();
if (!resBody.isEmpty()) {

View file

@ -678,15 +678,13 @@ public class VMManager {
}
public static boolean isthiscommandsafe(@NonNull String _command, Context _context) {
//xterm -e bash -c '
String result = _command.replaceFirst("(?i)^\\s*xterm\\s+-e\\s+bash\\s+-c\\s*'", "");
Log.d("VMManager.isthiscommandsafe", result);
Log.d("VMManager.isthiscommandsafe", _command);
if (result.startsWith("qemu")) {
if (!result.contains("&")) {
if (!result.contains("\n")) {
if (!result.contains(";")) {
if (!result.contains("|")) {
if (_command.startsWith("qemu")) {
if (!_command.contains("&")) {
if (!_command.contains("\n")) {
if (!_command.contains(";")) {
if (!_command.contains("|")) {
return true;
} else {
latestUnsafeCommandReason = _context.getString(R.string.command_are_not_allowed_to_contain_vertical_bars);

View file

@ -46,6 +46,7 @@ public class HomeStartVM {
public static String pendingVMID = "";
public static String pendingThumbnailFile = "";
public static boolean isLaunchFromPending = false;
public static String runCommandFormat = "export TMPDIR=/tmp && mkdir -p $TMPDIR/pulse && export XDG_RUNTIME_DIR=/tmp && pulseaudio --start --exit-idle-time=-1 > /dev/null 2>&1 && %s";
public static void startNow(
Activity activity,
@ -62,10 +63,11 @@ public class HomeStartVM {
} else {
if (MainSettingsManager.getVmUi(activity).equals("X11")) {
pendingVMName = vmName;
pendingEnv = "xterm -e bash -c '" + env + "'";
pendingEnv = env;
pendingVMID = vmID;
pendingThumbnailFile = thumbnailFile;
DisplaySystem.launch(activity);
runCommandFormat = String.format(runCommandFormat, "xterm -e bash -c '%s'");
return;
}
}
@ -164,11 +166,14 @@ public class HomeStartVM {
VMManager.isQemuStopedWithError = false;
String finalCommand = String.format(runCommandFormat, env);
Log.i(TAG, finalCommand);
if (ServiceUtils.isServiceRunning(activity, MainService.class)) {
MainService.startCommand(env, activity);
MainService.startCommand(finalCommand, activity);
} else {
Intent serviceIntent = new Intent(activity, MainService.class);
MainService.env = env;
MainService.env = finalCommand;
MainService.CHANNEL_ID = vmName;
MainService.activity = activity;
if (SDK_INT >= Build.VERSION_CODES.O) {
@ -222,11 +227,13 @@ public class HomeStartVM {
Log.d("HomeStartVM", i + ": " + params[i]);
}
setDefault();
}
public static void startPending(Activity activity) {
isLaunchFromPending = true;
startNow(activity, pendingVMName, pendingEnv, pendingVMID, pendingThumbnailFile);
setDefault();
}
public static void showProgressDialog(Activity activity, String _content, String thumbnailFile) {
@ -265,4 +272,8 @@ public class HomeStartVM {
progressDialog.show();
}
public static void setDefault() {
runCommandFormat = "export TMPDIR=/tmp && mkdir -p $TMPDIR/pulse && export XDG_RUNTIME_DIR=/tmp && pulseaudio --start --exit-idle-time=-1 > /dev/null 2>&1 && %s";
}
}

View file

@ -54,12 +54,8 @@ import com.vectras.vm.utils.PermissionUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
@ -86,6 +82,7 @@ public class SetupWizardActivity extends AppCompatActivity {
private boolean isServerError = false;
private boolean isManualMode = false;
private boolean isAllowCheckPermissions = false;
String tarPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -201,8 +198,6 @@ public class SetupWizardActivity extends AppCompatActivity {
checkpermissions();
}
String tarPath;
// Function to append text and automatically scroll to bottom
@SuppressLint("SetTextI18n")
private void appendTextAndScroll(String textToAdd) {
@ -284,6 +279,8 @@ public class SetupWizardActivity extends AppCompatActivity {
cmd += " echo \"Just a sec...\";" +
" apk add qemu-audio-sdl pulseaudio;" +
" echo export TMPDIR=/tmp >> /etc/profile;" +
" mkdir -p $TMPDIR/pulse;" +
" echo export PULSE_SERVER=127.0.0.1 >> /etc/profile;" +
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;" +
" echo \"installation successful! xssFjnj58Id\"";
@ -300,14 +297,8 @@ public class SetupWizardActivity extends AppCompatActivity {
isFirstLaunch = true;
SetupFeatureCore.checkabi(this);
File tarGZ = new File(tarPath);
if (tarGZ.exists()) {
isManualMode = true;
startSetup();
} else {
if (binding.linearsimplesetupui.getVisibility() == View.GONE) {
showAdvancedSetupDialog();
}
if (binding.linearsimplesetupui.getVisibility() == View.GONE) {
showAdvancedSetupDialog();
}
}
@ -354,54 +345,19 @@ public class SetupWizardActivity extends AppCompatActivity {
private final ActivityResultLauncher<String> bootstrapFilePicker =
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
File selectedFilePath = new File(getPath(uri));
String abi = Build.SUPPORTED_ABIS[0];
if (selectedFilePath.toString().endsWith(abi + ".tar.gz")) {
if (FileUtils.getFileNameFromUri(this, uri).endsWith(abi + ".tar.gz")) {
simpleSetupUIControler(1);
new Thread(() -> {
FileInputStream File = null;
try {
File = (FileInputStream) getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
setTextStatus(getString(R.string.copying_file));
FileUtils.copyFileFromUri(this, uri, tarPath);
runOnUiThread(() -> {
DialogUtils.oneDialog(this,
getString(R.string.oops),
getString(R.string.the_file_could_not_be_processed_content),
getResources().getString(R.string.ok),
true,
R.drawable.warning_48px,
true,
null,
() -> {
if (binding.linearsimplesetupui.getVisibility() == View.GONE) {
showAdvancedSetupDialog();
}
});
simpleSetupUIControler(0);
isManualMode = true;
startSetup();
MainSettingsManager.setsetUpWithManualSetupBefore(SetupWizardActivity.this, true);
});
}
try {
try {
try (OutputStream out = new FileOutputStream(tarPath)) {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while (true) {
assert File != null;
if (!((len = File.read(buf)) > 0)) break;
out.write(buf, 0, len);
}
}
} finally {
runOnUiThread(() -> {
isManualMode = true;
startSetup();
MainSettingsManager.setsetUpWithManualSetupBefore(SetupWizardActivity.this, true);
});
assert File != null;
File.close();
}
} catch (IOException e) {
} catch (Exception e) {
runOnUiThread(() -> {
DialogUtils.oneDialog(this,
getString(R.string.oops),
@ -422,8 +378,8 @@ public class SetupWizardActivity extends AppCompatActivity {
}).start();
} else {
DialogUtils.oneDialog(this,
"Invalid file",
"Please select vectras-vm-" + abi + ".tar.gz file.",
getString(R.string.invalid_file),
getString(R.string.please_select) + " vectras-vm-" + abi + ".tar.gz.",
getResources().getString(R.string.ok),
true,
R.drawable.warning_48px,

View file

@ -11,6 +11,7 @@ import android.net.Uri;
import android.os.Build;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.LayoutInflater;
@ -52,7 +53,9 @@ public class DialogUtils {
title.setText(_title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Spannable sp = (Spannable) Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY);
Spannable sp = (Spannable) (isHTML(_message) ?
Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY) :
new SpannableString(_message));
Linkify.addLinks(sp, Linkify.ALL);
content.setText(sp);
content.setMovementMethod(LinkMovementMethod.getInstance());
@ -110,7 +113,9 @@ public class DialogUtils {
title.setText(_title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Spannable sp = (Spannable) Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY);
Spannable sp = (Spannable) (isHTML(_message) ?
Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY) :
new SpannableString(_message));
Linkify.addLinks(sp, Linkify.ALL);
content.setText(sp);
content.setMovementMethod(LinkMovementMethod.getInstance());
@ -169,7 +174,9 @@ public class DialogUtils {
title.setText(_title);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Spannable sp = (Spannable) Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY);
Spannable sp = (Spannable) (isHTML(_message) ?
Html.fromHtml(_message, Html.FROM_HTML_MODE_LEGACY) :
new SpannableString(_message));
Linkify.addLinks(sp, Linkify.ALL);
content.setText(sp);
content.setMovementMethod(LinkMovementMethod.getInstance());
@ -269,4 +276,8 @@ public class DialogUtils {
);
}
}
public static boolean isHTML(String content) {
return content.contains("<") && content.contains("</") && content.contains(">");
}
}

View file

@ -105,7 +105,7 @@ public class Terminal {
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");
@ -199,7 +199,7 @@ public class Terminal {
//processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
//processBuilder.environment().put("LD_LIBRARY_PATH", TermuxService.PREFIX_PATH + "/lib");
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");
@ -303,7 +303,7 @@ public class Terminal {
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");
@ -381,7 +381,7 @@ public class Terminal {
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");
@ -499,7 +499,7 @@ public class Terminal {
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", user);
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", DISPLAY);
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");

View file

@ -170,7 +170,7 @@ public class TerminalBottomSheetDialog {
//processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
//processBuilder.environment().put("LD_LIBRARY_PATH", TermuxService.PREFIX_PATH + "/lib");
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("TMPDIR", "/tmp");
processBuilder.environment().put("SHELL", "/bin/sh");
processBuilder.environment().put("DISPLAY", ":0");
processBuilder.environment().put("PULSE_SERVER", "127.0.0.1");

View file

@ -3,7 +3,7 @@
<string name="app_name">Vectras VM</string>
<!--======================VECTRAS STRINGS====================-->
<string name="app_version" translatable="false">3.3.1</string>
<string name="app_version" translatable="false">3.3.2</string>
<string name="qemu_version" translatable="false">Stable</string>
<string name="str_home">Home</string>
<string name="str_logger">Logger</string>
@ -608,6 +608,7 @@
<string name="system_files_installation_failed_content">An error occurred while installing system files.</string>
<string name="copying_file">Copying file…</string>
<string name="cdrom_hint">CD-ROM (iso file only)</string>
<string name="invalid_file">Invalid file</string>
<!--======================TERMUX STRINGS====================-->

View file

@ -5,11 +5,11 @@
"url": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases/tag/3.3.0",
"Message": "<h2>3.3.0</h2>New Qemu 9.2.2 with 3dfx! And bugs fixed.",
"cancellable": true,
"versionCodeBeta":"35",
"versionNameBeta":"3.3.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.0,3.3.1",
"versionCodeBeta":"36",
"versionNameBeta":"3.3.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",
"sizeBeta": "60 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>3.3.1</h2>Bugs fixed.",
"MessageBeta": "<h2>3.3.2</h2>Bugs fixed.",
"cancellableBeta": true
}