Compare commits
16 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f99c74ecd | ||
|
|
3990bbb4c8 | ||
|
|
5074600e8b | ||
|
|
24a63b4311 | ||
|
|
fcdcab3b15 | ||
|
|
582d1d9845 | ||
|
|
661be39c3b | ||
|
|
30c98c3c17 | ||
|
|
cb32dffb89 | ||
|
|
08dcd03614 | ||
|
|
1735664e6c | ||
|
|
809bd1a3c3 | ||
|
|
a531e2331b | ||
|
|
6b00df5785 | ||
|
|
56dd71a355 | ||
|
|
71614fa6ff |
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"projects": {
|
||||
"default": "vectras-1678b"
|
||||
}
|
||||
}
|
||||
1
.github/ISSUE_TEMPLATE/bug.yaml
vendored
|
|
@ -32,6 +32,7 @@ body:
|
|||
options:
|
||||
- Latest
|
||||
- Beta
|
||||
- 4.3.0
|
||||
- 4.2.0
|
||||
- 4.1.0
|
||||
- 4.0.0
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ android {
|
|||
applicationId "com.vectras.vm"
|
||||
minSdk minApi
|
||||
targetSdk targetApi
|
||||
versionCode 134
|
||||
versionName "4.3.0"
|
||||
versionCode 137
|
||||
versionName "4.3.3"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
||||
|
|
|
|||
|
|
@ -299,6 +299,11 @@
|
|||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="10.0" />
|
||||
|
||||
<activity
|
||||
android:name=".settings.EqualizerActivity"
|
||||
android:exported="false"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1188,6 +1188,18 @@ public class MainSettingsManager extends AppCompatActivity
|
|||
return prefs.getInt("standardSetupVersion", 0);
|
||||
}
|
||||
|
||||
public static void setCoreSetupVersion(Context context, int value) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putInt("coreSetupVersion", value);
|
||||
edit.apply();
|
||||
}
|
||||
|
||||
public static int getCoreSetupVersion(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getInt("coreSetupVersion", 0);
|
||||
}
|
||||
|
||||
public static void setShowLastCrashLog(Context context, Boolean _boolean) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
|
|
@ -1329,6 +1341,6 @@ public class MainSettingsManager extends AppCompatActivity
|
|||
|
||||
public static Boolean getAutoSwitchToExternalMouse(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getBoolean("autoSwitchToExternalMouse", true);
|
||||
return prefs.getBoolean("autoSwitchToExternalMouse", false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ import com.vectras.vm.utils.DialogUtils;
|
|||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.ListUtils;
|
||||
import com.vectras.vm.utils.SimulateKeyEvent;
|
||||
import com.vectras.vm.utils.StreamAudio;
|
||||
import com.vectras.vm.sound.StreamAudio;
|
||||
import com.vectras.vm.utils.UIUtils;
|
||||
import com.vectras.vm.view.DynamicBubble;
|
||||
|
||||
|
|
@ -397,7 +397,7 @@ public class MainVNCActivity extends VncCanvasActivity {
|
|||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
this.stopTimeListener();
|
||||
if (streamAudio != null) streamAudio.stop();
|
||||
if (streamAudio != null) streamAudio.release();
|
||||
//Terminal.killQemuProcess();
|
||||
}
|
||||
|
||||
|
|
@ -774,8 +774,14 @@ public class MainVNCActivity extends VncCanvasActivity {
|
|||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "onMonitor: ", e);
|
||||
}
|
||||
monitorMode = true;
|
||||
vncCanvas.sendMetaKey1(50, 6);
|
||||
|
||||
try {
|
||||
vncCanvas.sendMetaKey1(50, 6);
|
||||
monitorMode = true;
|
||||
} catch (NullPointerException e) {
|
||||
monitorMode = false;
|
||||
Log.e(TAG, "onMonitor: ", e);
|
||||
}
|
||||
|
||||
});
|
||||
t.start();
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public class AboutActivity extends AppCompatActivity implements View.OnClickList
|
|||
|
||||
TextView qemuVersion = findViewById(R.id.qemuVersion);
|
||||
executor.execute(() -> {
|
||||
String qemuVersionName = CommandUtils.getQemuVersionName();
|
||||
String qemuVersionName = CommandUtils.getQemuVersionName(this);
|
||||
runOnUiThread(() -> {
|
||||
if (!qemuVersionName.isEmpty()) qemuVersion.setText(qemuVersionName); else getString(R.string.unknow);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public class AppConfig {
|
|||
public static String vectrasVersion;
|
||||
public static int vectrasVersionCode;
|
||||
public static final int standardSetupVersion = 922202606;
|
||||
public static final int coreSetupVersion = 0;
|
||||
public static String vectrasWebsite = "https://vectras.vercel.app/";
|
||||
public static String vectrasWebsiteRaw = "https://raw.githubusercontent.com/AnBui2004/Vectras-VM-Emu-Android/refs/heads/master/web/";
|
||||
public static String bootstrapfileslink = vectrasWebsiteRaw + "/data/setupfiles3.json";
|
||||
|
|
@ -78,13 +79,13 @@ public class AppConfig {
|
|||
|
||||
public static String neededPkgs() {
|
||||
if (DeviceUtils.isArm()) {
|
||||
return "bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
return "sudo bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
" libusbredirparser usbredir-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 capstone libcbor snappy lzo ndctl keyutils-libs vde2-libs libdw libbpf sndio-libs linux-pam fuse3-libs libssh vte3 iasl perl";
|
||||
} else {
|
||||
return "bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
return "sudo bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
" libusbredirparser usbredir-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" +
|
||||
|
|
@ -94,13 +95,13 @@ public class AppConfig {
|
|||
|
||||
public static String neededPkgs32bit() {
|
||||
if (DeviceUtils.isArm()) {
|
||||
return "bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
return "sudo bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
" libusbredirparser usbredir-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" +
|
||||
" qemu-audio-sdl capstone libcbor snappy lzo ndctl keyutils-libs vde2-libs libdw libbpf sndio-libs linux-pam fuse3-libs libssh vte3 iasl perl";
|
||||
} else {
|
||||
return "bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
return "sudo bash aria2 tar dwm xterm libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +
|
||||
" libusbredirparser usbredir-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" +
|
||||
|
|
@ -119,4 +120,5 @@ public class AppConfig {
|
|||
public static String virtIOWinUrl = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.285-1/virtio-win.iso";
|
||||
public static String virtIOWinUrlMd5 = "9e650d0e7c6e017a91ca299c8f7ed766";
|
||||
|
||||
public static boolean isGmsAvailable = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import com.vectras.vm.R;
|
|||
import com.vectras.vm.manager.VmFileManager;
|
||||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vm.utils.ProgressDialog;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
|
|
@ -99,8 +99,8 @@ public class CreateImageDialogFragment extends DialogFragment {
|
|||
progressDialog.show();
|
||||
|
||||
new Thread(() -> {
|
||||
String result = Terminal.executeShellCommandWithResult("qemu-img create -f qcow2 \"" + folder + Objects.requireNonNull(imageName.getText()) + ".qcow2\" " +
|
||||
Objects.requireNonNull(imageSize.getText()) + "G", requireActivity()).trim();
|
||||
String result = new Terminal2(requireContext()).executeOnThisThread("qemu-img create -f qcow2 \"" + folder + Objects.requireNonNull(imageName.getText()) + ".qcow2\" " +
|
||||
Objects.requireNonNull(imageSize.getText()) + "G").trim();
|
||||
|
||||
if (isMarkPendingAdd) VmFileManager.markPendingAdd(folder + Objects.requireNonNull(imageName.getText()) + ".qcow2");
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.vectras.vm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
|
|
@ -8,21 +9,28 @@ import android.app.Service;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.vectras.vm.main.core.MainStartVM;
|
||||
import com.vectras.vm.manager.VmServiceManager;
|
||||
import com.vectras.vm.utils.ClipboardUltils;
|
||||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainService extends Service {
|
||||
public static String CHANNEL_ID = "Vectras VM Service";
|
||||
private final int NOTIFICATION_ID = 1;
|
||||
private final String MACHINE_NAME = "Vectras VM";
|
||||
public static String vmName = "Vectras VM";
|
||||
public static String env = null;
|
||||
private String TAG = "MainService";
|
||||
private static String TAG = "MainService";
|
||||
public static MainService service;
|
||||
public static Context activityContext;
|
||||
|
||||
|
|
@ -42,7 +50,7 @@ public class MainService extends Service {
|
|||
|
||||
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText(MACHINE_NAME + " running in background.")
|
||||
.setContentText("The virtual machines are running...")
|
||||
.setSmallIcon(R.drawable.ic_vectras_vm_48)
|
||||
.addAction(R.drawable.close_24px, getString(R.string.stop), pStopSelf)
|
||||
.build();
|
||||
|
|
@ -51,8 +59,7 @@ public class MainService extends Service {
|
|||
|
||||
if (env != null) {
|
||||
if (service != null) {
|
||||
Terminal vterm = new Terminal(activityContext);
|
||||
vterm.executeShellCommand2(env, true, activityContext);
|
||||
startCommand(vmName, env, activityContext);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "env is null");
|
||||
|
|
@ -72,10 +79,13 @@ public class MainService extends Service {
|
|||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent != null && Objects.equals(intent.getAction(), STOP_ACTION)) {
|
||||
VMManager.killallqemuprocesses(this);
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
new Thread(() -> {
|
||||
VMManager.killallqemuprocesses(this);
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
|
@ -97,8 +107,55 @@ public class MainService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
public static void startCommand(String _env, Context _context) {
|
||||
Terminal vterm = new Terminal(_context);
|
||||
vterm.executeShellCommand2(_env, true, _context);
|
||||
public static void startCommand(String vmName, String env, Context context) {
|
||||
Terminal2 terminal2 = new Terminal2(activityContext);
|
||||
terminal2.setDefaultShellBash();
|
||||
terminal2.setStartup("export XDG_RUNTIME_DIR=/tmp && unset PULSE_SERVER");
|
||||
terminal2.execute(env, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
if (context instanceof Activity activity) {
|
||||
if (activity.isFinishing() || activity.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "context is not an Activity");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(log.trim().isEmpty() || log.trim().equals(MainStartVM.TAG_FINISHED_WITHOUT_ERROR))) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (!VMManager.isExecutedCommandError(command, log, context)) {
|
||||
String finalLog = log.contains(MainStartVM.TAG_FINISHED_WITHOUT_ERROR) ? log.substring(0, log.lastIndexOf(MainStartVM.TAG_FINISHED_WITHOUT_ERROR) - 1) : log;
|
||||
|
||||
DialogUtils.twoDialog(context, vmName, finalLog, context.getString(R.string.copy), context.getString(R.string.close), true, R.drawable.stack_24px, true,
|
||||
() -> ClipboardUltils.copyToClipboard(context, log), null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
VmServiceManager.stopService(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
if (context instanceof Activity activity) {
|
||||
if (activity.isFinishing() || activity.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "context is not an Activity");
|
||||
return;
|
||||
}
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> DialogUtils.twoDialog(context, "Execution Result", exception.getMessage(), context.getString(R.string.copy), context.getString(R.string.close), true, R.drawable.round_terminal_24, true,
|
||||
() -> ClipboardUltils.copyToClipboard(context, exception.getMessage()), null, null));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +126,12 @@ public class SplashActivity extends AppCompatActivity {
|
|||
if (MainSettingsManager.getShowLastCrashLog(this)) {
|
||||
startActivity(new Intent(this, LastCrashActivity.class));
|
||||
} else if (SetupFeatureCore.isInstalledQemu(this)) {
|
||||
if (MainSettingsManager.getStandardSetupVersion(this) != AppConfig.standardSetupVersion &&
|
||||
if (MainSettingsManager.getCoreSetupVersion(this) != AppConfig.coreSetupVersion) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("action", SetupWizard2Activity.ACTION_CORE_SYSTEM_UPDATE);
|
||||
intent.setClass(this, SetupWizard2Activity.class);
|
||||
startActivity(intent);
|
||||
} else if (MainSettingsManager.getStandardSetupVersion(this) != AppConfig.standardSetupVersion &&
|
||||
!MainSettingsManager.getsetUpWithManualSetupBefore(this)) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("action", SetupWizard2Activity.ACTION_SYSTEM_UPDATE);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.vectras.qemu.Config;
|
||||
import com.vectras.qemu.MainSettingsManager;
|
||||
|
|
@ -37,6 +38,7 @@ import com.vectras.vm.utils.JSONUtils;
|
|||
import com.vectras.vm.utils.ProgressDialog;
|
||||
import com.vectras.vm.utils.TextUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
|
|
@ -70,8 +72,14 @@ public class VMManager {
|
|||
|
||||
if (!JSONUtils.isValidFromString(vmJsonListContent) || vmId.isEmpty()) return false;
|
||||
|
||||
ArrayList<HashMap<String, Object>> vmList = new Gson().fromJson(vmJsonListContent, new TypeToken<ArrayList<HashMap<String, Object>>>() {
|
||||
}.getType());
|
||||
ArrayList<HashMap<String, Object>> vmList;
|
||||
|
||||
try {
|
||||
vmList = new Gson().fromJson(vmJsonListContent, new TypeToken<ArrayList<HashMap<String, Object>>>() {
|
||||
}.getType());
|
||||
} catch (JsonSyntaxException e) {
|
||||
return JSONUtils.isValidFromFile(VmFileManager.getConfigFile(vmId));
|
||||
}
|
||||
|
||||
if (vmList == null) return false;
|
||||
|
||||
|
|
@ -658,8 +666,6 @@ public class VMManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
VmServiceManager.stopService(_activity);
|
||||
|
||||
if (_command.contains("qemu-system") && _result.contains("Killed")) {
|
||||
isQemuStopedWithError = true;
|
||||
return true;
|
||||
|
|
@ -727,7 +733,7 @@ public class VMManager {
|
|||
},
|
||||
null, null);
|
||||
return false;
|
||||
} else if (_command.contains("qemu-system") && _result.contains("qemu-system") && !_result.contains("warning:")) {
|
||||
} else if (!_result.contains(MainStartVM.TAG_FINISHED_WITHOUT_ERROR)) {
|
||||
//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, R.drawable.error_96px);
|
||||
_activity.stopService(new Intent(_activity, MainService.class));
|
||||
|
|
@ -841,7 +847,7 @@ public class VMManager {
|
|||
}
|
||||
|
||||
public static boolean isVMRunning(Context context, String vmID) {
|
||||
String result = Terminal.executeShellCommandWithResult("ps -e", context);
|
||||
String result = new Terminal2(context).executeOnThisThread("ps -e");
|
||||
if (result.contains(" -qmp unix:" + Config.getLocalQMPSocketPath(vmID))) {
|
||||
Log.d("VMManager.isThisVMRunning", "Yes.\n\n" + result);
|
||||
return true;
|
||||
|
|
@ -858,18 +864,6 @@ public class VMManager {
|
|||
return exists;
|
||||
}
|
||||
|
||||
public static boolean isQemuRunning(Activity activity) {
|
||||
Terminal vterm = new Terminal(activity);
|
||||
vterm.executeShellCommand2("ps -e", false, activity);
|
||||
if (AppConfig.temporaryLastedTerminalOutput.contains("qemu-system")) {
|
||||
Log.d("VMManager.isQemuRunning", "Yes");
|
||||
return true;
|
||||
} else {
|
||||
Log.d("VMManager.isQemuRunning", "No");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isHaveADisk(String env) {
|
||||
return env.contains("-drive") || env.contains("-hda") || env.contains("-hdb") || env.contains("-cdrom") || env.contains("-fda") || env.contains("-fdb");
|
||||
}
|
||||
|
|
@ -902,20 +896,8 @@ public class VMManager {
|
|||
}, null, null);
|
||||
}
|
||||
|
||||
public static void killcurrentqemuprocess(Activity activity) {
|
||||
Terminal vterm = new Terminal(activity);
|
||||
String qemuProcess = switch (MainSettingsManager.getArch(activity)) {
|
||||
case "ARM64" -> "qemu-system-aarch64";
|
||||
case "PPC" -> "qemu-system-ppc";
|
||||
case "I386" -> "qemu-system-i386";
|
||||
default -> "qemu-system-x86_64";
|
||||
};
|
||||
vterm.executeShellCommand2("killall -15 " + qemuProcess + "; sleep 1; killall -9 " + qemuProcess, false, null);
|
||||
}
|
||||
|
||||
public static void killallqemuprocesses(Context context) {
|
||||
Terminal vterm = new Terminal(context);
|
||||
vterm.executeShellCommand2("pkill -15 -f qemu-system-; sleep 1; pkill -9 -f qemu-system-", false, null);
|
||||
new Terminal2(context).executeOnThisThread("pkill -15 -f qemu-system-; sleep 1; pkill -9 -f qemu-system-");
|
||||
}
|
||||
|
||||
public static String startMigrate() {
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
|||
import com.vectras.qemu.Config;
|
||||
import com.vectras.qemu.MainSettingsManager;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.GmsChecker;
|
||||
import com.vectras.vm.utils.PackageUtils;
|
||||
import com.vectras.vm.utils.UIUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Locale;
|
||||
|
||||
public class VectrasApp extends Application {
|
||||
public static VectrasApp vectrasapp;
|
||||
|
|
@ -97,8 +97,14 @@ public class VectrasApp extends Application {
|
|||
}
|
||||
});
|
||||
|
||||
FirebaseAnalytics.getInstance(this).logEvent(FirebaseAnalytics.Event.APP_OPEN, null);
|
||||
FirebaseCrashlytics.getInstance().log("App started: " + AppConfig.vectrasVersion);
|
||||
|
||||
if (GmsChecker.isAvailable(this)) {
|
||||
AppConfig.isGmsAvailable = true;
|
||||
FirebaseAnalytics.getInstance(this).logEvent(FirebaseAnalytics.Event.APP_OPEN, null);
|
||||
} else {
|
||||
FirebaseCrashlytics.getInstance().log("Device does not support GMS.");
|
||||
}
|
||||
}
|
||||
|
||||
private void setupTheme() {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ import android.content.ComponentName;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
|
|
@ -63,6 +66,7 @@ import java.util.concurrent.Executors;
|
|||
import com.vectras.vm.utils.ZipUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vm.utils.PermissionUtils;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class VMCreatorActivity extends AppCompatActivity {
|
||||
|
||||
|
|
@ -309,9 +313,28 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
setDefault();
|
||||
if (MainSettingsManager.autoCreateDisk(this)) {
|
||||
if (createVMFolder(true)) {
|
||||
Terminal vterm = new Terminal(this);
|
||||
vterm.executeShellCommand2("qemu-img create -f qcow2 " + VmFileManager.getPath(vmID, "disk.qcow2") + " 128G", false, this);
|
||||
binding.drive.setText(VmFileManager.getPath(vmID, "disk.qcow2"));
|
||||
Terminal2 terminal2 = new Terminal2(this);
|
||||
terminal2.setShowProgressDialog(true);
|
||||
terminal2.execute("qemu-img create -f qcow2 " + VmFileManager.getPath(vmID, "disk.qcow2") + " 128G", new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (status == terminal2.SUCCESS)
|
||||
binding.drive.setText(VmFileManager.getPath(vmID, "disk.qcow2"));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(getApplicationContext(), getString(R.string.an_error_occurred_while_creating_the_virtual_drive), Toast.LENGTH_SHORT).show());
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setDrive(SELECT_DISK_0_FILE_MODE, null);
|
||||
|
|
@ -1156,7 +1179,7 @@ public class VMCreatorActivity extends AppCompatActivity {
|
|||
private void showProgressDialog(String message) {
|
||||
dialogProgressStyleBinding.progressText.setText(message);
|
||||
dialogProgressStyleBinding.progressBar.setIndeterminate(true);
|
||||
progressDialog.show();
|
||||
if (!isFinishing() && !isDestroyed()) progressDialog.show();
|
||||
}
|
||||
|
||||
private String copyToTemp(Uri uri) throws IOException {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@ package com.vectras.vm.fcm;
|
|||
import android.util.Log;
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.vectras.vm.AppConfig;
|
||||
|
||||
public class FCMManager {
|
||||
private static final String TAG = "FCMManager";
|
||||
|
||||
public static void subscribe() {
|
||||
if (!AppConfig.isGmsAvailable) return;
|
||||
|
||||
FirebaseMessaging.getInstance()
|
||||
.subscribeToTopic("vectrasvmandroidgithub")
|
||||
.addOnCompleteListener(task -> {
|
||||
|
|
@ -20,6 +23,8 @@ public class FCMManager {
|
|||
}
|
||||
|
||||
public static void unSubscribe() {
|
||||
if (!AppConfig.isGmsAvailable) return;
|
||||
|
||||
FirebaseMessaging.getInstance()
|
||||
.unsubscribeFromTopic("vectrasvmandroidgithub")
|
||||
.addOnCompleteListener(task -> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import static com.vectras.vm.utils.LibraryChecker.isPackageInstalled2;
|
|||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.termux.app.TermuxService;
|
||||
|
|
@ -21,6 +23,7 @@ import com.vectras.vm.utils.FileUtils;
|
|||
import com.vectras.vm.utils.PackageUtils;
|
||||
import com.vectras.vm.x11.X11Activity;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -86,8 +89,32 @@ public class DisplaySystem {
|
|||
R.drawable.desktop_24px,
|
||||
true,
|
||||
() -> {
|
||||
String installCommand = "apk add " + necessaryPackage;
|
||||
new Terminal(context).executeShellCommand(installCommand, true, true, context.getString(R.string.just_a_moment), context);
|
||||
String installCommand = "apk add " + necessaryPackage + " && echo \"Installed: " + necessaryPackage + "\"";
|
||||
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
terminal2.setShowProgressDialog(true);
|
||||
terminal2.execute(installCommand, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (status == terminal2.SUCCESS) {
|
||||
launchX11(context, isKill);
|
||||
} else {
|
||||
DialogUtils.oopsDialog(context, log);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> DialogUtils.oopsDialog(context, exception.getMessage()));
|
||||
}
|
||||
});
|
||||
},
|
||||
null,
|
||||
null
|
||||
|
|
@ -116,7 +143,9 @@ public class DisplaySystem {
|
|||
}
|
||||
|
||||
public static void startDesktop(Context context) {
|
||||
new Terminal(context).executeShellCommand2("export DISPLAY=:0 && fluxbox > /dev/null", false, context);
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
terminal2.setDefaultShellBash();
|
||||
terminal2.execute("export DISPLAY=:0 && fluxbox > /dev/null");
|
||||
}
|
||||
|
||||
public static void startTermuxX11(Context context) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import java.io.File;
|
|||
|
||||
public class MainStartVM {
|
||||
public static final String TAG = "HomeStartVM";
|
||||
public static final String TAG_FINISHED_WITHOUT_ERROR = "This VM has shut down.";
|
||||
public static boolean skipIDEwithARM64DialogInStartVM = false;
|
||||
public static boolean breakNow = false;
|
||||
public static final Handler handlerForLaunch = new Handler(Looper.getMainLooper());
|
||||
|
|
@ -50,7 +51,7 @@ public class MainStartVM {
|
|||
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 && chmod -R 775 $TMPDIR/pulse && pulseaudio --start --exit-idle-time=-1 > /dev/null 2>&1 && %s";
|
||||
public static String runCommandFormat = "%s";
|
||||
|
||||
private static StartVmDialog dialog;
|
||||
|
||||
|
|
@ -297,7 +298,7 @@ public class MainStartVM {
|
|||
) {
|
||||
VMManager.isQemuStopedWithError = false;
|
||||
|
||||
String cleanUpCommand = "; rm -r " + Config.getCacheVMPath(vmID);
|
||||
String cleanUpCommand = " && echo \"" + TAG_FINISHED_WITHOUT_ERROR + "\"\nrm -r " + Config.getCacheVMPath(vmID);
|
||||
|
||||
String finalCommand = VMManager.addAudioDevWav(vmID, String.format(runCommandFormat, env + cleanUpCommand));
|
||||
|
||||
|
|
@ -314,11 +315,12 @@ public class MainStartVM {
|
|||
}
|
||||
|
||||
if (ServiceUtils.isServiceRunning(context, MainService.class)) {
|
||||
MainService.startCommand(finalCommand, context);
|
||||
MainService.startCommand(vmName, finalCommand, context);
|
||||
} else {
|
||||
Intent serviceIntent = new Intent(context, MainService.class);
|
||||
MainService.activityContext = context;
|
||||
MainService.env = finalCommand;
|
||||
MainService.vmName = vmName;
|
||||
MainService.CHANNEL_ID = vmName;
|
||||
if (SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(serviceIntent);
|
||||
|
|
@ -488,6 +490,6 @@ public class MainStartVM {
|
|||
}
|
||||
|
||||
public static void setDefault() {
|
||||
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";
|
||||
runCommandFormat = "%s";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.vectras.vm.main.core;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
|
@ -13,6 +15,7 @@ import com.vectras.vm.manager.VmFileManager;
|
|||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class PendingCommand {
|
||||
private static final String TAG = "PendingCommand";
|
||||
|
|
@ -49,9 +52,30 @@ public class PendingCommand {
|
|||
null
|
||||
);
|
||||
} else {
|
||||
Terminal _vterm = new Terminal(activity);
|
||||
_vterm.executeShellCommand2(command, false, activity);
|
||||
Toast.makeText(activity, activity.getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
|
||||
Terminal2 terminal2 = new Terminal2(activity);
|
||||
terminal2.setShowProgressDialog(true);
|
||||
terminal2.execute(command, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (status == terminal2.SUCCESS) {
|
||||
Toast.makeText(activity, activity.getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toast.makeText(activity, activity.getResources().getString(R.string.an_error_occurred_while_creating_the_virtual_drive), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(activity, activity.getResources().getString(R.string.an_error_occurred_while_creating_the_virtual_drive), Toast.LENGTH_LONG).show());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
command = "";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.vectras.vm.main.core;
|
|||
import android.app.Activity;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
|
@ -92,31 +93,38 @@ public class StartVmDialog {
|
|||
|
||||
boolean isVmRuning = VMManager.isVMRunning(activity, vmId);
|
||||
|
||||
while (isVmRuning) {
|
||||
Config.vmID = vmId;
|
||||
if (!isVmRuning) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
isShuttingDown = false;
|
||||
dismiss();
|
||||
});
|
||||
} else {
|
||||
while (true) {
|
||||
Config.vmID = vmId;
|
||||
|
||||
isVmRuning = VMManager.isVMRunning(activity, vmId);
|
||||
isVmRuning = VMManager.isVMRunning(activity, vmId);
|
||||
|
||||
QmpSender.shutdown();
|
||||
QmpSender.shutdown();
|
||||
|
||||
if (!isVmRuning || VMManager.isQemuStopedWithError || triedCount == MAX_TRY) {
|
||||
if (triedCount < MAX_TRY) FileUtils.delete(Config.getLocalQMPSocketPath(vmId));
|
||||
if (!isVmRuning || VMManager.isQemuStopedWithError || triedCount >= MAX_TRY) {
|
||||
if (triedCount < MAX_TRY) FileUtils.delete(Config.getLocalQMPSocketPath(vmId));
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
isShuttingDown = false;
|
||||
dismiss();
|
||||
});
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
isShuttingDown = false;
|
||||
dismiss();
|
||||
});
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ignored) {
|
||||
|
||||
}
|
||||
|
||||
triedCount++;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ignored) {
|
||||
|
||||
}
|
||||
|
||||
triedCount++;
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
|
|
@ -126,7 +134,7 @@ public class StartVmDialog {
|
|||
.setCancelable(false)
|
||||
.create();
|
||||
|
||||
progressDialog.show();
|
||||
if (!activity.isFinishing() && !activity.isDestroyed()) progressDialog.show();
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.vectras.vm.manager.QmpSender;
|
|||
import com.vectras.vm.utils.CommandUtils;
|
||||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
|
@ -229,10 +230,10 @@ public class SystemMonitorFragment extends Fragment {
|
|||
binding.tvQemuarch.setText(getString(R.string.arch) + " " + currentArch + ".");
|
||||
|
||||
executor.execute(() -> {
|
||||
String qemuVersionName = CommandUtils.getQemuVersionName();
|
||||
String qemuVersionName = CommandUtils.getQemuVersionName(requireContext());
|
||||
|
||||
if (!isAdded()) return;
|
||||
String result = Terminal.executeShellCommandWithResult("ps -e command && echo \"psendhere\" && cat /proc/cpuinfo", requireActivity());
|
||||
String result = new Terminal2(requireContext()).executeOnThisThread("ps -e command && echo \"psendhere\" && cat /proc/cpuinfo");
|
||||
|
||||
if (!isAdded()) return;
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.vectras.vm.setupwizard.SetupFeatureCore;
|
|||
import com.vectras.vm.utils.DeviceUtils;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
|
@ -51,7 +52,7 @@ public class BatteryEmulatorManager {
|
|||
FileUtils.writeToFile(vmTemp.getAbsolutePath(), "battery.asl", batteryAsl);
|
||||
|
||||
if (FileUtils.isFileExists(VmFileManager.getTempPath(context, vmId, "battery.asl"))) {
|
||||
String respond = Terminal.executeShellCommandWithResult("cd " + vmTemp.getAbsolutePath() + " && iasl battery.asl && echo Compiled", context);
|
||||
String respond = new Terminal2(context).executeOnThisThread("cd " + vmTemp.getAbsolutePath() + " && iasl battery.asl && echo Compiled");
|
||||
//Log.d(TAG, respond);
|
||||
return respond.contains("Compiled");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.vectras.vm.utils.ClipboardUltils;
|
|||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vm.utils.ProgressDialog;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class HostSharedFolder {
|
||||
public static final String TAG = "HostSharedFolder";
|
||||
|
|
@ -25,13 +26,16 @@ public class HostSharedFolder {
|
|||
|
||||
new Thread(() -> {
|
||||
boolean isRuning;
|
||||
if (Terminal.executeShellCommandWithResult("pgrep -f 'http.server 19000'", context).isEmpty()) {
|
||||
if (!Terminal.executeShellCommandWithResult("which python3", context).contains("python3"))
|
||||
Terminal.executeShellCommandWithResult("apk add python3", context);
|
||||
|
||||
startCommand(context);
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
|
||||
isRuning = !Terminal.executeShellCommandWithResult("sleep 1; pgrep -f 'http.server 19000'", context).isEmpty();
|
||||
if (terminal2.executeOnThisThread("pgrep -f 'http.server 19000'").isEmpty()) {
|
||||
if (!terminal2.executeOnThisThread("which python3").contains("python3"))
|
||||
terminal2.executeOnThisThread("apk add python3");
|
||||
|
||||
new Terminal2(context).execute("python3 -m http.server 19000 --bind 127.0.0.1 --directory " + SHARED_DIR);
|
||||
|
||||
isRuning = !terminal2.executeOnThisThread("sleep 1; pgrep -f 'http.server 19000'").isEmpty();
|
||||
} else {
|
||||
isRuning = true;
|
||||
}
|
||||
|
|
@ -61,9 +65,4 @@ public class HostSharedFolder {
|
|||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void startCommand(Context _context) {
|
||||
Terminal vterm = new Terminal(_context);
|
||||
vterm.executeShellCommand2("python3 -m http.server 19000 --bind 127.0.0.1 --directory " + SHARED_DIR, false, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package com.vectras.vm.manager;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class ProcessManager {
|
||||
public static boolean isQemuRunning(Context context) {
|
||||
return Terminal.executeShellCommandWithResult("ps -e", context).contains("qemu-system-");
|
||||
return new Terminal2(context).executeOnThisThread("ps -e").contains("qemu-system-");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ import android.content.Context;
|
|||
|
||||
import com.vectras.qemu.MainSettingsManager;
|
||||
import com.vectras.vm.settings.ItemSettingsSelector;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class QemuManager {
|
||||
public static final int DEFAULT_REFRESH_RATE = 60;
|
||||
public static final int DEFAULT_LOW_REFRESH_RATE = 30;
|
||||
|
||||
public static boolean isSupportSetRefreshRate(Context context) {
|
||||
return Terminal.executeShellCommandWithResult(getQemuExecutableFile(context) + " -vnc help", context).contains("refresh-rate");
|
||||
return new Terminal2(context).executeOnThisThread(getQemuExecutableFile(context) + " -vnc help").contains("refresh-rate");
|
||||
}
|
||||
|
||||
public static boolean isSupportAcpiTable(Context context) {
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ public class QmpSender {
|
|||
public static String changeDevice(String deviceId, String filePath) {
|
||||
if (filePath.trim().isEmpty()) return ejectDevice(deviceId);
|
||||
|
||||
return send("change " + deviceId + " " + filePath);
|
||||
return send("change " + deviceId + " \"" + filePath + "\"");
|
||||
}
|
||||
|
||||
public static void quickEjectDevice(Context context, String deviceId) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.util.Log;
|
|||
import com.vectras.qemu.Config;
|
||||
import com.vectras.vm.VectrasApp;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.StreamAudio;
|
||||
import com.vectras.vm.sound.StreamAudio;
|
||||
|
||||
public class VmAudioManager {
|
||||
private static final String TAG = "VmAudioManager";
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import com.vectras.vm.settings.VNCSettingsActivity;
|
|||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.ProgressDialog;
|
||||
import com.vectras.vm.utils.StreamAudio;
|
||||
import com.vectras.vm.sound.StreamAudio;
|
||||
import com.vectras.vm.x11.X11Activity;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -667,7 +667,14 @@ public class VmControllerDialog extends DialogFragment {
|
|||
if (uri != null) {
|
||||
try {
|
||||
new Thread(() -> {
|
||||
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
|
||||
String filePath = FileUtils.getPath(getContext(), uri);
|
||||
|
||||
if (filePath == null) {
|
||||
showErrorSelectedFileDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
File selectedFilePath = new File(filePath);
|
||||
|
||||
if (isAdded()) {
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
|
|
|
|||
195
app/src/main/java/com/vectras/vm/settings/EqualizerActivity.java
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
package com.vectras.vm.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.vectras.vm.R;
|
||||
import com.vectras.vm.databinding.ActivityEqualizerBinding;
|
||||
import com.vectras.vm.sound.AudioSettingsData;
|
||||
import com.vectras.vm.sound.SoundEffect;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EqualizerActivity extends AppCompatActivity {
|
||||
|
||||
ActivityEqualizerBinding binding;
|
||||
AudioSettingsData audioSettingsData;
|
||||
float[] lastValues = new float[5];
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.undo) {
|
||||
binding.sliderUpperTreble.setValue(lastValues[0]);
|
||||
binding.sliderTreble.setValue(lastValues[1]);
|
||||
binding.sliderMid.setValue(lastValues[2]);
|
||||
binding.sliderBass.setValue(lastValues[3]);
|
||||
binding.sliderLowBass.setValue(lastValues[4]);
|
||||
return true;
|
||||
} else if (id == R.id.reset) {
|
||||
binding.sliderUpperTreble.setValue(0);
|
||||
binding.sliderTreble.setValue(0);
|
||||
binding.sliderMid.setValue(0);
|
||||
binding.sliderBass.setValue(0);
|
||||
binding.sliderLowBass.setValue(0);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.equalizer_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
EdgeToEdge.enable(this);
|
||||
binding = ActivityEqualizerBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbar);
|
||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||
binding.toolbar.setNavigationOnClickListener(view -> finish());
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (audioSettingsData != null) {
|
||||
audioSettingsData.setEqualizerEnabled(binding.swEnabled.isChecked());
|
||||
audioSettingsData.setUpperTreble(binding.sliderUpperTreble.getValue());
|
||||
audioSettingsData.setTreble(binding.sliderTreble.getValue());
|
||||
audioSettingsData.setMid(binding.sliderMid.getValue());
|
||||
audioSettingsData.setBass(binding.sliderBass.getValue());
|
||||
audioSettingsData.setLowBass(binding.sliderLowBass.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
SoundEffect soundEffect = new SoundEffect(this, 0);
|
||||
short bands = soundEffect.equalizer.getNumberOfBands();
|
||||
|
||||
if (bands < 2) {
|
||||
binding.lnUnsupport.setVisibility(View.VISIBLE);
|
||||
binding.appbar.setVisibility(View.GONE);
|
||||
binding.lnEnabled.setVisibility(View.GONE);
|
||||
binding.lnAllOptions.setVisibility(View.GONE);
|
||||
binding.btnExit.setOnClickListener(v -> finish());
|
||||
return;
|
||||
}
|
||||
|
||||
audioSettingsData = new AudioSettingsData(this);
|
||||
|
||||
lastValues[0] = audioSettingsData.getUpperTreble();
|
||||
lastValues[1] = audioSettingsData.getTreble();
|
||||
lastValues[2] = audioSettingsData.getMid();
|
||||
lastValues[3] = audioSettingsData.getBass();
|
||||
lastValues[4] = audioSettingsData.getLowBass();
|
||||
|
||||
|
||||
// 1dB = 100mB
|
||||
int minBandLevelRange = soundEffect.getMinBandLevelRange() / 100;
|
||||
int maxBandLevelRange = soundEffect.getMaxBandLevelRange() / 100;
|
||||
|
||||
if (bands > 4) {
|
||||
binding.sliderLowBass.setValueFrom(minBandLevelRange);
|
||||
binding.sliderLowBass.setValueTo(maxBandLevelRange);
|
||||
|
||||
binding.sliderLowBass.setValue(audioSettingsData.getLowBass());
|
||||
|
||||
binding.tvLowBassValue.setText(getFormattedValue(binding.sliderLowBass.getValue()));
|
||||
|
||||
binding.sliderLowBass.addOnChangeListener((slider, value, fromUser) -> binding.tvLowBassValue.setText(getFormattedValue(value)));
|
||||
} else {
|
||||
binding.lnLowBass.setVisibility(View.GONE);
|
||||
binding.tvUpperTreble.setText(R.string.upper_treble);
|
||||
binding.tvTreble.setText(R.string.treble);
|
||||
binding.tvMid.setText(R.string.bass);
|
||||
binding.tvBass.setText(R.string.low_bass);
|
||||
}
|
||||
|
||||
if (bands > 3) {
|
||||
binding.sliderBass.setValueFrom(minBandLevelRange);
|
||||
binding.sliderBass.setValueTo(maxBandLevelRange);
|
||||
|
||||
binding.sliderBass.setValue(audioSettingsData.getBass());
|
||||
|
||||
binding.tvBassValue.setText(getFormattedValue(binding.sliderBass.getValue()));
|
||||
|
||||
binding.sliderBass.addOnChangeListener((slider, value, fromUser) -> binding.tvBassValue.setText(getFormattedValue(value)));
|
||||
} else {
|
||||
binding.lnBass.setVisibility(View.GONE);
|
||||
binding.tvUpperTreble.setText(R.string.treble);
|
||||
binding.tvTreble.setText(R.string.mid);
|
||||
binding.tvMid.setText(R.string.bass);
|
||||
}
|
||||
|
||||
if (bands > 2) {
|
||||
binding.sliderMid.setValueFrom(minBandLevelRange);
|
||||
binding.sliderMid.setValueTo(maxBandLevelRange);
|
||||
|
||||
binding.sliderMid.setValue(audioSettingsData.getMid());
|
||||
|
||||
binding.tvMidValue.setText(getFormattedValue(binding.sliderMid.getValue()));
|
||||
|
||||
binding.sliderMid.addOnChangeListener((slider, value, fromUser) -> binding.tvMidValue.setText(getFormattedValue(value)));
|
||||
} else {
|
||||
binding.lnMid.setVisibility(View.GONE);
|
||||
binding.tvUpperTreble.setText(R.string.treble);
|
||||
binding.tvTreble.setText(R.string.bass);
|
||||
}
|
||||
|
||||
binding.sliderUpperTreble.setValueFrom(minBandLevelRange);
|
||||
binding.sliderUpperTreble.setValueTo(maxBandLevelRange);
|
||||
|
||||
binding.sliderTreble.setValueFrom(minBandLevelRange);
|
||||
binding.sliderTreble.setValueTo(maxBandLevelRange);
|
||||
|
||||
|
||||
binding.sliderUpperTreble.setValue(audioSettingsData.getUpperTreble());
|
||||
binding.sliderTreble.setValue(audioSettingsData.getTreble());
|
||||
|
||||
|
||||
binding.tvUpperTrebleValue.setText(getFormattedValue(binding.sliderUpperTreble.getValue()));
|
||||
binding.tvTrebleValue.setText(getFormattedValue(binding.sliderTreble.getValue()));
|
||||
|
||||
|
||||
binding.sliderUpperTreble.addOnChangeListener((slider, value, fromUser) -> binding.tvUpperTrebleValue.setText(getFormattedValue(value)));
|
||||
binding.sliderTreble.addOnChangeListener((slider, value, fromUser) -> binding.tvTrebleValue.setText(getFormattedValue(value)));
|
||||
|
||||
|
||||
binding.lnEnabled.setOnClickListener(v -> binding.swEnabled.toggle());
|
||||
binding.swEnabled.setChecked(audioSettingsData.isEqualizerEnabled());
|
||||
binding.swEnabled.setOnCheckedChangeListener((buttonView, isChecked) -> setEnabled(isChecked));
|
||||
|
||||
|
||||
setEnabled(binding.swEnabled.isChecked());
|
||||
}
|
||||
|
||||
private void setEnabled(boolean isEnabled) {
|
||||
binding.lnAllOptions.setAlpha(isEnabled ? 1 : 0.5f);
|
||||
binding.sliderUpperTreble.setEnabled(isEnabled);
|
||||
binding.sliderTreble.setEnabled(isEnabled);
|
||||
binding.sliderMid.setEnabled(isEnabled);
|
||||
binding.sliderBass.setEnabled(isEnabled);
|
||||
binding.sliderLowBass.setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
DecimalFormat decimalFormat = new DecimalFormat("#.#");
|
||||
|
||||
private String getFormattedValue(float value) {
|
||||
return decimalFormat.format(value) + " dB";
|
||||
}
|
||||
}
|
||||
|
|
@ -42,5 +42,7 @@ public class Settings2Activity extends AppCompatActivity {
|
|||
|
||||
binding.lnVnc.setOnClickListener(v -> startActivity(new Intent(this, VNCSettingsActivity.class)));
|
||||
binding.lnX11.setOnClickListener(v -> startActivity(new Intent(this, X11DisplaySettingsActivity.class)));
|
||||
|
||||
binding.lnEqualizer.setOnClickListener(v -> startActivity(new Intent(this, EqualizerActivity.class)));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package com.vectras.vm.setupwizard;
|
|||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vectras.vm.R;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package com.vectras.vm.setupwizard;
|
||||
|
||||
import static android.content.Intent.ACTION_VIEW;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
|
|
@ -13,10 +10,8 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.transition.TransitionManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
|
|
@ -29,7 +24,6 @@ import com.anbui.elephant.retrofit2utils.Retrofit2Utils;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.termux.app.TermuxActivity;
|
||||
import com.termux.app.TermuxService;
|
||||
import com.vectras.qemu.MainSettingsManager;
|
||||
import com.vectras.vm.AppConfig;
|
||||
import com.vectras.vm.R;
|
||||
|
|
@ -37,7 +31,6 @@ import com.vectras.vm.VMManager;
|
|||
import com.vectras.vm.creator.VMCreatorSelector;
|
||||
import com.vectras.vm.databinding.ActivitySetupWizard2Binding;
|
||||
import com.vectras.vm.databinding.SetupQemuDoneBinding;
|
||||
import com.vectras.vm.databinding.SimpleLayoutListViewWithCheckBinding;
|
||||
import com.vectras.vm.main.MainActivity;
|
||||
import com.vectras.vm.utils.DeviceUtils;
|
||||
import com.vectras.vm.utils.DialogUtils;
|
||||
|
|
@ -48,14 +41,9 @@ import com.vectras.vm.utils.ListUtils;
|
|||
import com.vectras.vm.utils.PermissionUtils;
|
||||
import com.vectras.vm.utils.TarUtils;
|
||||
import com.vectras.vm.utils.UIUtils;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
import com.vectras.vterm.TerminalBottomSheetDialog;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
|
@ -66,6 +54,8 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
ActivitySetupWizard2Binding binding;
|
||||
SetupQemuDoneBinding bindingFinalSteps;
|
||||
public static final int ACTION_SYSTEM_UPDATE = 1;
|
||||
public static final int ACTION_CORE_SYSTEM_UPDATE = 2;
|
||||
int ACTION;
|
||||
final int STEP_REQUEST_PERMISSION = 1;
|
||||
final int STEP_EXTRACTING_SYSTEM_FILES = 2;
|
||||
final int STEP_GETTING_DATA = 3;
|
||||
|
|
@ -84,7 +74,6 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
String downloadBootstrapsCommand = "";
|
||||
String tarPath = "";
|
||||
String progressText ="0%";
|
||||
boolean isSystemUpdateMode = false;
|
||||
boolean isExecutingCommand = false;
|
||||
boolean isLibProotError = false;
|
||||
boolean aria2Error = false;
|
||||
|
|
@ -188,7 +177,7 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
});
|
||||
|
||||
binding.btnTryAgain.setOnClickListener(v -> {
|
||||
if (isSystemUpdateMode) {
|
||||
if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
uiController(STEP_SYSTEM_UPDATE);
|
||||
binding.btnSkipSystemUpdate.setVisibility(View.GONE);
|
||||
} else if (isLibProotError) {
|
||||
|
|
@ -232,16 +221,22 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
uiController(STEP_EXTRACTING_SYSTEM_FILES);
|
||||
new Thread(() -> {
|
||||
VMManager.killallqemuprocesses(this);
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/data");
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/distro");
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/usr");
|
||||
if (ACTION == ACTION_CORE_SYSTEM_UPDATE) {
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/data");
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/distro");
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/usr");
|
||||
}
|
||||
runOnUiThread(this::extractSystemFiles);
|
||||
}).start();
|
||||
});
|
||||
|
||||
if (getIntent().hasExtra("action")) {
|
||||
if (getIntent().getIntExtra("action", -1) == ACTION_SYSTEM_UPDATE) {
|
||||
isSystemUpdateMode = true;
|
||||
ACTION = getIntent().getIntExtra("action", -1);
|
||||
|
||||
if (ACTION == ACTION_CORE_SYSTEM_UPDATE) {
|
||||
uiController(STEP_SYSTEM_UPDATE);
|
||||
binding.btnSkipSystemUpdate.setVisibility(View.GONE);
|
||||
} else if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
uiController(STEP_SYSTEM_UPDATE);
|
||||
}
|
||||
}
|
||||
|
|
@ -379,6 +374,11 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void extractSystemFiles() {
|
||||
if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
getDataForStandardSetup();
|
||||
return;
|
||||
}
|
||||
|
||||
uiController(STEP_EXTRACTING_SYSTEM_FILES);
|
||||
|
||||
executor.execute(() -> {
|
||||
|
|
@ -423,7 +423,7 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (isSystemUpdateMode) {
|
||||
if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
startSetup();
|
||||
} else {
|
||||
uiController(STEP_SETUP_OPTIONS);
|
||||
|
|
@ -431,6 +431,7 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
}, 1000);
|
||||
} else {
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> uiController(STEP_SETUP_OPTIONS), 1000);
|
||||
Log.e("SetupWizard2Activity", "getDataForStandardSetup: " + error);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -465,32 +466,46 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
" apk update;" +
|
||||
" echo \"Installing packages...\";" +
|
||||
" apk add " + (DeviceUtils.is64bit() ? AppConfig.neededPkgs()
|
||||
: AppConfig.neededPkgs32bit()) + ";" +
|
||||
" echo \"Downloading Qemu...\";";
|
||||
: AppConfig.neededPkgs32bit()) + ";";
|
||||
|
||||
if (isCustomSetupMode) {
|
||||
cmd += " tar -xzvf " + tarPath + " -C /;" +
|
||||
" rm " + tarPath + ";" +
|
||||
" chmod 775 /usr/local/bin/*;";
|
||||
} else {
|
||||
if (FileUtils.isFileExists(getFilesDir().getAbsolutePath() + "/distro/root/setup.tar.gz"))
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/distro/root/setup.tar.gz");
|
||||
|
||||
cmd += downloadBootstrapsCommand + ";" +
|
||||
if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
cmd += "echo \"Uninstalling...\";" +
|
||||
" rm -f /usr/local/bin/qemu-*;" +
|
||||
" rm -f /usr/share/applications/qemu.desktop;" +
|
||||
" rm -f /usr/share/icons/hicolor/*/qemu.png;" +
|
||||
" rm -rf /usr/share/qemu;" +
|
||||
downloadBootstrapsCommand + ";" +
|
||||
" echo \"Installing Qemu...\";" +
|
||||
" tar -xzvf setup.tar.gz -C /;" +
|
||||
" rm setup.tar.gz;" +
|
||||
" chmod 775 /usr/local/bin/*;";
|
||||
} else {
|
||||
if (isCustomSetupMode) {
|
||||
cmd += " echo \"Installing Qemu...\";" +
|
||||
" tar -xzvf " + tarPath + " -C /;" +
|
||||
" rm " + tarPath + ";" +
|
||||
" chmod 775 /usr/local/bin/*;" +
|
||||
" echo \"Just a sec...\";" +
|
||||
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;";
|
||||
} else {
|
||||
if (FileUtils.isFileExists(getFilesDir().getAbsolutePath() + "/distro/root/setup.tar.gz"))
|
||||
FileUtils.delete(getFilesDir().getAbsolutePath() + "/distro/root/setup.tar.gz");
|
||||
|
||||
cmd += " echo \"Downloading Qemu...\";" +
|
||||
downloadBootstrapsCommand + ";" +
|
||||
" echo \"Installing Qemu...\";" +
|
||||
" tar -xzvf setup.tar.gz -C /;" +
|
||||
" rm setup.tar.gz;" +
|
||||
" chmod 775 /usr/local/bin/*;" +
|
||||
" echo \"Just a sec...\";" +
|
||||
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
cmd += " echo \"Just a sec...\";" +
|
||||
" 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\"";
|
||||
cmd += " echo \"Installation successful! xssFjnj58Id\"";
|
||||
|
||||
executeShellCommand(cmd);
|
||||
execute(cmd);
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
|
@ -526,83 +541,17 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
}
|
||||
});
|
||||
|
||||
public void executeShellCommand(String userCommand) {
|
||||
isExecutingCommand = true;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Set up the process builder to start PRoot with environmental variables and commands
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
private void execute(String command) {
|
||||
Terminal2 terminal2 = new Terminal2(this);
|
||||
terminal2.execute(command, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
runOnUiThread(() -> appendTextAndScroll(newLine + "\n"));
|
||||
}
|
||||
|
||||
// Adjust these environment variables as necessary for your app
|
||||
String filesDir = getFilesDir().getAbsolutePath();
|
||||
|
||||
File tmpDir = new File(getFilesDir(), "usr/tmp");
|
||||
|
||||
// Setup environment for the PRoot process
|
||||
processBuilder.environment().put("PROOT_TMP_DIR", tmpDir.getAbsolutePath());
|
||||
|
||||
processBuilder.environment().put("HOME", "/root");
|
||||
processBuilder.environment().put("USER", "root");
|
||||
processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
|
||||
processBuilder.environment().put("TERM", "xterm-256color");
|
||||
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
|
||||
processBuilder.environment().put("SHELL", "/bin/sh");
|
||||
|
||||
String[] prootCommand = {
|
||||
TermuxService.PREFIX_PATH + "/bin/proot", // PRoot binary path
|
||||
"--kill-on-exit",
|
||||
"--link2symlink",
|
||||
"-0",
|
||||
"-r", filesDir + "/distro", // Path to the rootfs
|
||||
"-b", "/dev",
|
||||
"-b", "/proc",
|
||||
"-b", "/sys",
|
||||
"-b", "/sdcard",
|
||||
"-b", "/storage",
|
||||
"-b", "/data",
|
||||
"-w", "/root",
|
||||
"/bin/sh",
|
||||
"--login"// The shell to execute inside PRoot
|
||||
};
|
||||
|
||||
processBuilder.command(prootCommand);
|
||||
Process process = processBuilder.start();
|
||||
// Get the input and output streams of the process
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
|
||||
// Send user command to PRoot
|
||||
writer.write(userCommand);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
// Read the input stream for the output of the command
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
final String outputLine = line;
|
||||
runOnUiThread(() -> appendTextAndScroll(outputLine + "\n"));
|
||||
}
|
||||
|
||||
// Read any errors from the error stream
|
||||
while ((line = errorReader.readLine()) != null) {
|
||||
final String errorLine = line;
|
||||
runOnUiThread(() -> appendTextAndScroll(errorLine + "\n"));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
reader.close();
|
||||
errorReader.close();
|
||||
|
||||
// Wait for the process to finish
|
||||
process.waitFor();
|
||||
|
||||
// Wait for the process to finish
|
||||
int exitValue = process.waitFor();
|
||||
|
||||
// Check if the exit value indicates an error
|
||||
if (exitValue != 0) {
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
if (status != terminal2.SUCCESS) {
|
||||
isExecutingCommand = false;
|
||||
if (aria2Error && downloadBootstrapsCommand.contains("aria2c")) {
|
||||
runOnUiThread(() -> {
|
||||
|
|
@ -611,22 +560,22 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
});
|
||||
} else {
|
||||
runOnUiThread(() -> {
|
||||
String toastMessage = "Command failed with exit code: " + exitValue;
|
||||
String toastMessage = "Command failed with exit code: " + status;
|
||||
appendTextAndScroll("Error: " + toastMessage + "\n");
|
||||
uiController(STEP_ERROR, logs);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
isExecutingCommand = false;
|
||||
// Handle exceptions by printing the stack trace in the terminal output
|
||||
final String errorMessage = e.getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
runOnUiThread(() -> {
|
||||
appendTextAndScroll("Error: " + errorMessage + "\n");
|
||||
appendTextAndScroll("Error: " + exception.getMessage() + "\n");
|
||||
uiController(STEP_ERROR, logs);
|
||||
});
|
||||
}
|
||||
}).start(); // Execute the command in a separate thread to prevent blocking the UI thread
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
|
@ -636,9 +585,10 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
if (newLog.contains("xssFjnj58Id")) {
|
||||
isExecutingCommand = false;
|
||||
MainSettingsManager.setStandardSetupVersion(this, AppConfig.standardSetupVersion);
|
||||
MainSettingsManager.setCoreSetupVersion(this, AppConfig.coreSetupVersion);
|
||||
MainSettingsManager.setsetUpWithManualSetupBefore(this, isCustomSetupMode);
|
||||
uiController(STEP_JOIN_COMMUNITY);
|
||||
if (isSystemUpdateMode) {
|
||||
if (ACTION == ACTION_SYSTEM_UPDATE) {
|
||||
uiControllerFinalSteps(STEP_FINISH);
|
||||
}
|
||||
} else if (newLog.contains("libproot.so --help") || newLog.contains("/bin/sh: can't fork:")) {
|
||||
|
|
@ -694,65 +644,6 @@ public class SetupWizard2Activity extends AppCompatActivity {
|
|||
}), getString(R.string.mirrors));
|
||||
}
|
||||
|
||||
public static class SpinnerSelectMirrorAdapter extends BaseAdapter {
|
||||
|
||||
private final ArrayList<HashMap<String, String>> data;
|
||||
private final LayoutInflater inflater;
|
||||
private final int selectedPosition;
|
||||
|
||||
public SpinnerSelectMirrorAdapter(Context context, ArrayList<HashMap<String, String>> arr) {
|
||||
this.data = arr;
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.selectedPosition = MainSettingsManager.getSelectedMirror(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> getItem(int position) {
|
||||
return data.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
SetupWizard2Activity.SpinnerSelectMirrorAdapter.ViewHolder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
// Inflate binding only once for each new item
|
||||
SimpleLayoutListViewWithCheckBinding simpleLayoutListViewWithCheckBinding =
|
||||
SimpleLayoutListViewWithCheckBinding.inflate(inflater, parent, false);
|
||||
|
||||
// Create ViewHolder to hold binding
|
||||
holder = new SetupWizard2Activity.SpinnerSelectMirrorAdapter.ViewHolder(simpleLayoutListViewWithCheckBinding);
|
||||
convertView = simpleLayoutListViewWithCheckBinding.getRoot();
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
// Get back the saved ViewHolder
|
||||
holder = (SetupWizard2Activity.SpinnerSelectMirrorAdapter.ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
// Assign data
|
||||
HashMap<String, String> item = data.get(position);
|
||||
holder.simpleLayoutListViewWithCheckBinding.textview.setText(item.get("location"));
|
||||
holder.simpleLayoutListViewWithCheckBinding.ivCheck.setVisibility(position == selectedPosition ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
// ViewHolder holds binding for reuse
|
||||
private record ViewHolder(SimpleLayoutListViewWithCheckBinding simpleLayoutListViewWithCheckBinding) {
|
||||
}
|
||||
}
|
||||
|
||||
public String getPath(Uri uri) {
|
||||
return FileUtils.getPath(this, uri);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package com.vectras.vm.sound;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class AudioSettingsData {
|
||||
Context context;
|
||||
SharedPreferences sharedPreferences;
|
||||
|
||||
public AudioSettingsData(Context context) {
|
||||
this.context = context;
|
||||
sharedPreferences = context.getSharedPreferences("audio_settings", Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public void setEqualizerEnabled(boolean enabled) {
|
||||
sharedPreferences.edit().putBoolean("isEnabled", enabled).apply();
|
||||
}
|
||||
|
||||
public boolean isEqualizerEnabled() {
|
||||
return sharedPreferences.getBoolean("isEnabled", false);
|
||||
}
|
||||
|
||||
public void setUpperTreble(float value) {
|
||||
sharedPreferences.edit().putFloat("upperTreble", value).apply();
|
||||
}
|
||||
|
||||
public float getUpperTreble() {
|
||||
return sharedPreferences.getFloat("upperTreble", 0);
|
||||
}
|
||||
|
||||
public void setTreble(float value) {
|
||||
sharedPreferences.edit().putFloat("treble", value).apply();
|
||||
}
|
||||
|
||||
public float getTreble() {
|
||||
return sharedPreferences.getFloat("treble", 0);
|
||||
}
|
||||
|
||||
public void setMid(float value) {
|
||||
sharedPreferences.edit().putFloat("mid", value).apply();
|
||||
}
|
||||
|
||||
public float getMid() {
|
||||
return sharedPreferences.getFloat("mid", 0);
|
||||
}
|
||||
|
||||
public void setBass(float value) {
|
||||
sharedPreferences.edit().putFloat("bass", value).apply();
|
||||
}
|
||||
|
||||
public float getBass() {
|
||||
return sharedPreferences.getFloat("bass", 0);
|
||||
}
|
||||
|
||||
public void setLowBass(float value) {
|
||||
sharedPreferences.edit().putFloat("lowBass", value).apply();
|
||||
}
|
||||
|
||||
public float getLowBass() {
|
||||
return sharedPreferences.getFloat("lowBass", 0);
|
||||
}
|
||||
}
|
||||
118
app/src/main/java/com/vectras/vm/sound/SoundEffect.java
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
package com.vectras.vm.sound;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.audiofx.Equalizer;
|
||||
import android.util.Log;
|
||||
|
||||
public class SoundEffect {
|
||||
final String TAG = "SoundEffect";
|
||||
|
||||
Context context;
|
||||
public int session;
|
||||
public Equalizer equalizer;
|
||||
|
||||
public SoundEffect(Context context, int session) {
|
||||
this.context = context;
|
||||
this.session = session;
|
||||
|
||||
equalizer = new Equalizer(1000, session);
|
||||
}
|
||||
|
||||
public AudioFrequencyData getDeviceAudioFrequencies() {
|
||||
AudioFrequencyData data = new AudioFrequencyData();
|
||||
|
||||
int[] targets = { 60, 230, 910, 4000, 14000 };
|
||||
|
||||
short bands = equalizer.getNumberOfBands();
|
||||
int[] hzList = new int[bands];
|
||||
|
||||
for (short i = 0; i < bands; i++) {
|
||||
int center = equalizer.getCenterFreq(i);
|
||||
hzList[i] = center / 1000;
|
||||
}
|
||||
|
||||
if (bands <= targets.length) {
|
||||
int[] finalIds = new int[bands];
|
||||
for (int i = 0; i < bands; i++) {
|
||||
finalIds[i] = i;
|
||||
}
|
||||
|
||||
data.frequencies = hzList;
|
||||
data.ids = finalIds;
|
||||
|
||||
Log.d(TAG, "Equalizer bands: " + bands);
|
||||
Log.d(TAG, "Equalizer frequencies: " + hzList[0] + ", " + hzList[1] + ", " + hzList[2] + ", " + hzList[3] + ", " + hzList[4]);
|
||||
Log.d(TAG, "Equalizer ids: " + finalIds[0] + ", " + finalIds[1] + ", " + finalIds[2] + ", " + finalIds[3] + ", " + finalIds[4]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int[] finalHzList = new int[5];
|
||||
int[] finalIds = new int[5];
|
||||
|
||||
for (int i = 0; i < targets.length; i++) {
|
||||
int losest = Integer.MAX_VALUE;
|
||||
int bandId = 0;
|
||||
for (int ii = 0; ii < hzList.length; ii++) {
|
||||
if (Math.abs(targets[i] - hzList[ii]) < losest) {
|
||||
losest = hzList[ii];
|
||||
bandId = ii;
|
||||
}
|
||||
|
||||
finalHzList[i] = losest;
|
||||
finalIds[i] = bandId;
|
||||
}
|
||||
}
|
||||
|
||||
data.frequencies = finalHzList;
|
||||
data.ids = finalIds;
|
||||
|
||||
Log.d(TAG, "Equalizer bands: " + bands);
|
||||
Log.d(TAG, "Equalizer frequencies: " + hzList[0] + ", " + hzList[1] + ", " + hzList[2] + ", " + hzList[3] + ", " + hzList[4]);
|
||||
Log.d(TAG, "Equalizer ids: " + finalIds[0] + ", " + finalIds[1] + ", " + finalIds[2] + ", " + finalIds[3] + ", " + finalIds[4]);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public void applyEffect(float[] dBData) {
|
||||
short bands = equalizer.getNumberOfBands();
|
||||
|
||||
if (bands < 2) {
|
||||
Log.d(TAG, "Equalizer bands: " + bands);
|
||||
return;
|
||||
}
|
||||
|
||||
AudioFrequencyData data = getDeviceAudioFrequencies();
|
||||
|
||||
equalizer.setBandLevel((short) data.ids[0], (short) dBData[0]);
|
||||
equalizer.setBandLevel((short) data.ids[1], (short) dBData[1]);
|
||||
if (bands > 2) equalizer.setBandLevel((short) data.ids[2], (short) dBData[2]);
|
||||
if (bands > 3) equalizer.setBandLevel((short) data.ids[3], (short) dBData[3]);
|
||||
if (bands > 4) equalizer.setBandLevel((short) data.ids[4], (short) dBData[4]);
|
||||
|
||||
Log.d(TAG, "Equalizer dB: " + dBData[0] + ", " + dBData[1] + ", " + dBData[2] + ", " + dBData[3] + ", " + dBData[4]);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (equalizer != null) {
|
||||
equalizer.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
equalizer.setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
public short getMinBandLevelRange() {
|
||||
return equalizer.getBandLevelRange()[0];
|
||||
}
|
||||
|
||||
public short getMaxBandLevelRange() {
|
||||
return equalizer.getBandLevelRange()[1];
|
||||
}
|
||||
|
||||
public static class AudioFrequencyData {
|
||||
int[] frequencies;
|
||||
int[] ids;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,15 @@
|
|||
package com.vectras.vm.utils;
|
||||
package com.vectras.vm.sound;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.audiofx.Equalizer;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class StreamAudio {
|
||||
|
|
@ -17,6 +20,7 @@ public class StreamAudio {
|
|||
private int sampleRate = 48000;
|
||||
public boolean isDestroyed;
|
||||
private StreamAudio cross;
|
||||
private SoundEffect soundEffect;
|
||||
|
||||
public StreamAudio(Context context) {
|
||||
this.context = context;
|
||||
|
|
@ -54,6 +58,10 @@ public class StreamAudio {
|
|||
sampleRate = 48000;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
isPlay = false;
|
||||
releaseSoundEffect();
|
||||
}
|
||||
|
||||
public void streamFromFile() {
|
||||
if (isPlay) return;
|
||||
|
|
@ -100,6 +108,8 @@ public class StreamAudio {
|
|||
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||
.build();
|
||||
|
||||
applyEffect(audioTrack);
|
||||
|
||||
audioTrack.play();
|
||||
|
||||
if (cross != null && !cross.isDestroyed && cross.isPlaying()) cross.stop();
|
||||
|
|
@ -133,6 +143,63 @@ public class StreamAudio {
|
|||
}).start();
|
||||
}
|
||||
|
||||
float[] currentdBData = new float[5];
|
||||
|
||||
public void applyEffect(AudioTrack audioTrack) {
|
||||
if (soundEffect != null && soundEffect.equalizer.getNumberOfBands() < 2) return;
|
||||
|
||||
AudioSettingsData audioSettingsData = new AudioSettingsData(context);
|
||||
|
||||
if (!audioSettingsData.isEqualizerEnabled()) {
|
||||
releaseSoundEffect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (soundEffect == null || soundEffect.session != audioTrack.getAudioSessionId())
|
||||
soundEffect = new SoundEffect(context, audioTrack.getAudioSessionId());
|
||||
|
||||
if (soundEffect.equalizer.getNumberOfBands() < 2) return;
|
||||
|
||||
float[] dBData = new float[5];
|
||||
|
||||
//Bass -> Mid -> Treble
|
||||
dBData[0] = audioSettingsData.getLowBass();
|
||||
dBData[1] = audioSettingsData.getBass();
|
||||
dBData[2] = audioSettingsData.getMid();
|
||||
dBData[3] = audioSettingsData.getTreble();
|
||||
dBData[4] = audioSettingsData.getUpperTreble();
|
||||
|
||||
if (
|
||||
currentdBData[0] == dBData[0] &&
|
||||
currentdBData[1] == dBData[1] &&
|
||||
currentdBData[2] == dBData[2] &&
|
||||
currentdBData[3] == dBData[3] &&
|
||||
currentdBData[4] == dBData[4]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentdBData = dBData;
|
||||
|
||||
// Convert dB to mB
|
||||
for (int i = 0; i < dBData.length; i++) {
|
||||
dBData[i] = dBData[i] * 100;
|
||||
}
|
||||
|
||||
soundEffect.applyEffect(dBData);
|
||||
|
||||
soundEffect.setEnabled(audioSettingsData.isEqualizerEnabled());
|
||||
|
||||
Log.d(TAG, "Equalizer enabled: " + audioSettingsData.isEqualizerEnabled());
|
||||
}
|
||||
|
||||
public void releaseSoundEffect() {
|
||||
if (soundEffect != null) {
|
||||
soundEffect.setEnabled(false);
|
||||
soundEffect.release();
|
||||
soundEffect = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isContextDestroyed(Context context) {
|
||||
if (context instanceof Activity activity) {
|
||||
isDestroyed = activity.isDestroyed() || activity.isFinishing();
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.vectras.vm.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import com.vectras.vm.VectrasApp;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
public class CommandUtils {
|
||||
public static String createForSelectedMirror(boolean _https, String _url, String _beforemain) {
|
||||
|
|
@ -18,24 +20,23 @@ public class CommandUtils {
|
|||
}
|
||||
|
||||
public static void run(String _command, boolean _isShowResult, Activity _activity) {
|
||||
Terminal vterm = new Terminal(_activity);
|
||||
vterm.executeShellCommand2(_command, _isShowResult, _activity);
|
||||
new Terminal2(_activity).execute(_command);
|
||||
}
|
||||
|
||||
public static String getQemuVersionName() {
|
||||
String qemuVersion = getQemuVersion();
|
||||
public static String getQemuVersionName(Context context) {
|
||||
String qemuVersion = getQemuVersion(context);
|
||||
|
||||
if (qemuVersion.toLowerCase().contains("failed") || qemuVersion.toLowerCase().contains("not found"))
|
||||
return "";
|
||||
|
||||
return (qemuVersion.contains("Error") ? qemuVersion.substring(0, qemuVersion.indexOf("Error")) : qemuVersion) + (is3dfxVersion() ? " - 3dfx" : "");
|
||||
return (qemuVersion.contains("Error") ? qemuVersion.substring(0, qemuVersion.indexOf("Error")) : qemuVersion) + (is3dfxVersion(context) ? " - 3dfx" : "");
|
||||
}
|
||||
|
||||
public static String getQemuVersion() {
|
||||
return VectrasApp.getContext() == null ? "Unknow" : Terminal.executeShellCommandWithResult("qemu-system-x86_64 --version | head -n1 | awk '{print $4}'", VectrasApp.getContext()).replaceAll("\n", "");
|
||||
public static String getQemuVersion(Context context) {
|
||||
return VectrasApp.getContext() == null ? "Unknow" : new Terminal2(context).executeOnThisThread("qemu-system-x86_64 --version | head -n1 | awk '{print $4}'").replaceAll("\n", "");
|
||||
}
|
||||
|
||||
public static boolean is3dfxVersion() {
|
||||
return VectrasApp.getContext() != null && Terminal.executeShellCommandWithResult("qemu-system-x86_64 --version", VectrasApp.getContext()).contains("3dfx");
|
||||
public static boolean is3dfxVersion(Context context) {
|
||||
return VectrasApp.getContext() != null && new Terminal2(context).executeOnThisThread("qemu-system-x86_64 --version").contains("3dfx");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,13 @@ public class DeviceUtils {
|
|||
}
|
||||
|
||||
public static boolean is64bit() {
|
||||
return new CpuHelper().is64Bit();
|
||||
try {
|
||||
return new CpuHelper().is64Bit();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
return Build.SUPPORTED_ABIS[0].contains("64") &&
|
||||
Build.SUPPORTED_64_BIT_ABIS != null &&
|
||||
Build.SUPPORTED_64_BIT_ABIS.length > 0;
|
||||
}
|
||||
}
|
||||
public static boolean isArm() {
|
||||
return Build.SUPPORTED_ABIS[0].contains("arm");
|
||||
|
|
|
|||
13
app/src/main/java/com/vectras/vm/utils/GmsChecker.java
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package com.vectras.vm.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
|
||||
public class GmsChecker {
|
||||
public static boolean isAvailable(Context context) {
|
||||
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
|
||||
return googleApiAvailability.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.vectras.vm.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -14,11 +16,14 @@ import java.util.HashMap;
|
|||
import java.util.Objects;
|
||||
|
||||
public class JSONUtils {
|
||||
private static final String TAG = "JSONUtils";
|
||||
|
||||
public static boolean isValidFromString(String _content) {
|
||||
try {
|
||||
JsonElement element = JsonParser.parseString(_content);
|
||||
return element != null;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "isValidFromString: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ package com.vectras.vm.utils;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.vectras.vm.AppConfig;
|
||||
import com.vectras.vm.R;
|
||||
import com.vectras.vterm.Terminal;
|
||||
import com.vectras.vterm.Terminal2;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -66,30 +68,69 @@ public class LibraryChecker {
|
|||
() -> {
|
||||
// Create the installation command
|
||||
String installCommand = "apk add " + missingLibraries.replace("\n", " ");
|
||||
new Terminal(context).executeShellCommand(installCommand, true, true, activity);
|
||||
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
terminal2.setShowProgressDialog(true);
|
||||
terminal2.execute(installCommand, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (status == terminal2.SUCCESS) {
|
||||
DialogUtils.oneDialog(
|
||||
activity,
|
||||
activity.getString(R.string.done),
|
||||
activity.getString(R.string.the_necessary_packages_have_been_installed),
|
||||
R.drawable.check_24px
|
||||
);
|
||||
} else {
|
||||
DialogUtils.oopsDialog(context, log);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> DialogUtils.oopsDialog(context, exception.getMessage()));
|
||||
}
|
||||
});
|
||||
},
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// Method to show the "All Libraries Installed" dialog
|
||||
private void showAllLibrariesInstalledDialog(Activity activity) {
|
||||
new AlertDialog.Builder(activity, R.style.MainDialogTheme)
|
||||
.setTitle("All Libraries Installed")
|
||||
.setMessage("All required libraries are already installed.")
|
||||
.setPositiveButton("OK", (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
|
||||
// Method to check if the package is installed
|
||||
public void isPackageInstalled(String packageName, Terminal.CommandCallback callback) {
|
||||
String command = "apk info";
|
||||
|
||||
Terminal terminal = new Terminal(context);
|
||||
terminal.executeShellCommand(command, (Activity) context, false, (output, errors) -> {
|
||||
if (callback != null) {
|
||||
callback.onCommandCompleted(output, errors);
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
terminal2.execute(command, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (callback != null) {
|
||||
if (status == terminal2.SUCCESS) {
|
||||
callback.onCommandCompleted(log, "");
|
||||
} else {
|
||||
callback.onCommandCompleted(log, log);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> callback.onCommandCompleted("", exception.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -98,59 +139,30 @@ public class LibraryChecker {
|
|||
public static void isPackageInstalled2(Context context, String packageName, Terminal.CommandCallback callback) {
|
||||
String command = "apk info";
|
||||
|
||||
Terminal terminal = new Terminal(context);
|
||||
terminal.executeShellCommand(command, context, false, (output, errors) -> {
|
||||
if (callback != null) {
|
||||
callback.onCommandCompleted(output, errors);
|
||||
Terminal2 terminal2 = new Terminal2(context);
|
||||
terminal2.execute(command, new Terminal2.Terminal2Callback() {
|
||||
@Override
|
||||
public void onRunning(String command, String newLine) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(String command, String log, int status) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (callback != null) {
|
||||
if (status == terminal2.SUCCESS) {
|
||||
callback.onCommandCompleted(log, "");
|
||||
} else {
|
||||
callback.onCommandCompleted(log, log);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String command, Exception exception) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> callback.onCommandCompleted("", exception.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void checkAndInstallXFCE4(Activity activity) {
|
||||
// XFCE4 meta-package
|
||||
String xfce4Package = "xfce4";
|
||||
|
||||
// Check if XFCE4 is installed
|
||||
isPackageInstalled(xfce4Package, (output, errors) -> {
|
||||
boolean isInstalled = false;
|
||||
|
||||
// Check if the package exists in the installed packages output
|
||||
if (output != null) {
|
||||
Set<String> installedPackages = new HashSet<>();
|
||||
for (String installedPackage : output.split("\n")) {
|
||||
installedPackages.add(installedPackage.trim());
|
||||
}
|
||||
|
||||
isInstalled = installedPackages.contains(xfce4Package.trim());
|
||||
}
|
||||
|
||||
// If not installed, show a dialog to install it
|
||||
if (!isInstalled) {
|
||||
showInstallDialog(activity, xfce4Package);
|
||||
} else {
|
||||
showAlreadyInstalledDialog(activity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showInstallDialog(Activity activity, String packageName) {
|
||||
new AlertDialog.Builder(activity, R.style.MainDialogTheme)
|
||||
.setTitle("Install XFCE4")
|
||||
.setMessage("XFCE4 is not installed. Would you like to install it?")
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("Install", (dialog, which) -> {
|
||||
String installCommand = "apk add " + packageName;
|
||||
new Terminal(context).executeShellCommand(installCommand, true, true, activity);
|
||||
})
|
||||
.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showAlreadyInstalledDialog(Activity activity) {
|
||||
new AlertDialog.Builder(activity, R.style.MainDialogTheme)
|
||||
.setTitle("XFCE4 Installed")
|
||||
.setMessage("XFCE4 is already installed on this system.")
|
||||
.setPositiveButton("OK", (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ public class DynamicBubble {
|
|||
}
|
||||
|
||||
private void setup() {
|
||||
bubble.animate().alpha(0.5f).setDuration(200);
|
||||
|
||||
bubble.setOnTouchListener((v, event) -> {
|
||||
switch (event.getActionMasked()) {
|
||||
|
||||
|
|
@ -44,6 +46,9 @@ public class DynamicBubble {
|
|||
|
||||
// If the displacement exceeds the threshold, it is determined that pulling is occurring.
|
||||
if (Math.abs(movedX) > CLICK_ACTION_THRESHOLD || Math.abs(movedY) > CLICK_ACTION_THRESHOLD) {
|
||||
|
||||
if (!isDragging) bubble.animate().alpha(1).setDuration(200);
|
||||
|
||||
isDragging = true;
|
||||
|
||||
// Move the view using your finger.
|
||||
|
|
@ -75,6 +80,8 @@ public class DynamicBubble {
|
|||
}
|
||||
|
||||
private void onDropped() {
|
||||
bubble.animate().alpha(0.5f).setDuration(200);
|
||||
|
||||
if (bubble.getX() > (float) container.getWidth() / 2) {
|
||||
bubble.animate().x(container.getWidth() - bubble.getWidth());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ package com.vectras.vm.x11;
|
|||
|
||||
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
|
||||
|
||||
import android.app.Dialog;
|
||||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
|
|
@ -16,8 +14,6 @@ import static android.view.InputDevice.KEYBOARD_TYPE_ALPHABETIC;
|
|||
import static android.view.KeyEvent.*;
|
||||
import static android.view.WindowManager.LayoutParams.*;
|
||||
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
|
|
@ -37,7 +33,7 @@ import com.vectras.vm.manager.VmFileManager;
|
|||
import com.vectras.vm.manager.VmListManager;
|
||||
import com.vectras.vm.manager.VmPicker;
|
||||
import com.vectras.vm.utils.DialogUtils;
|
||||
import com.vectras.vm.utils.StreamAudio;
|
||||
import com.vectras.vm.sound.StreamAudio;
|
||||
import com.vectras.vm.utils.UIUtils;
|
||||
|
||||
import static com.vectras.vm.x11.CmdEntryPoint.ACTION_START;
|
||||
|
|
@ -80,7 +76,6 @@ import android.view.Window;
|
|||
import android.view.WindowInsets;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -98,7 +93,6 @@ import com.vectras.vm.x11.utils.KeyInterceptor;
|
|||
import com.vectras.vm.x11.utils.TermuxX11ExtraKeys;
|
||||
import com.vectras.vm.x11.utils.X11ToolbarViewPager;
|
||||
import com.vectras.vm.R;
|
||||
import com.vectras.vterm.Terminal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -758,7 +752,7 @@ public class X11Activity extends AppCompatActivity implements View.OnApplyWindow
|
|||
@Override
|
||||
protected void onDestroy() {
|
||||
unregisterReceiver(receiver);
|
||||
if (streamAudio != null) streamAudio.stop();
|
||||
if (streamAudio != null) streamAudio.release();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
|
|
|||
253
app/src/main/java/com/vectras/vterm/Terminal2.java
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
package com.vectras.vterm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vectras.vm.AppConfig;
|
||||
import com.vectras.vm.R;
|
||||
import com.vectras.vm.logger.VectrasStatus;
|
||||
import com.vectras.vm.utils.FileUtils;
|
||||
import com.vectras.vm.utils.ProgressDialog;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class Terminal2 {
|
||||
final String TAG = "Terminal2";
|
||||
public final int SUCCESS = 0;
|
||||
public final int ERROR = 1;
|
||||
Context context;
|
||||
String user = "root";
|
||||
String home = "/root";
|
||||
String display = ":0";
|
||||
String shell = "/bin/sh";
|
||||
String startup = "";
|
||||
String logs = "";
|
||||
String lastLog = "";
|
||||
boolean isShowProgressDialog;
|
||||
|
||||
ProgressDialog progressDialog = null;
|
||||
|
||||
public interface Terminal2Callback {
|
||||
void onRunning(String command, String newLine);
|
||||
void onFinished(String command, String log, int status);
|
||||
void onError(String command, Exception exception);
|
||||
}
|
||||
|
||||
public Terminal2(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setUserName(String user) {
|
||||
this.user = user;
|
||||
home = user.equals("root") ? "/root" : "/home/" + user;
|
||||
}
|
||||
|
||||
public void setRootMode() {
|
||||
this.user = "root";
|
||||
home = "/root";
|
||||
}
|
||||
|
||||
public void setDefaultShell() {
|
||||
this.shell = "/bin/sh";
|
||||
}
|
||||
|
||||
public void setDefaultShellBash() {
|
||||
this.shell = "/bin/bash";
|
||||
}
|
||||
|
||||
public void setStartup(String command) {
|
||||
this.startup = command;
|
||||
}
|
||||
|
||||
public String getLogs() {
|
||||
return logs;
|
||||
}
|
||||
|
||||
public void clearLog() {
|
||||
logs = "";
|
||||
}
|
||||
|
||||
public void setShowProgressDialog(boolean isShow) {
|
||||
this.isShowProgressDialog = isShow;
|
||||
}
|
||||
|
||||
public String executeOnThisThread(String command) {
|
||||
execute(command, null, false);
|
||||
return lastLog;
|
||||
}
|
||||
|
||||
public void execute(String command) {
|
||||
execute(command, null);
|
||||
}
|
||||
|
||||
public void execute(String command, Terminal2Callback callback) {
|
||||
execute(command, callback, true);
|
||||
}
|
||||
|
||||
public void execute(String command, Terminal2Callback callback, boolean isNewThread) {
|
||||
AtomicReference<Process> process = new AtomicReference<>();
|
||||
|
||||
Runnable runnable = () -> {
|
||||
|
||||
if (isShowProgressDialog) {
|
||||
progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setText(context.getString(R.string.executing_command_please_wait));
|
||||
new Handler(Looper.getMainLooper()).post((progressDialog::show));
|
||||
}
|
||||
|
||||
try {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.redirectErrorStream(true);
|
||||
|
||||
|
||||
String filesDir = Objects.requireNonNull(context.getFilesDir().getAbsolutePath());
|
||||
String prootPath = new File(filesDir, "usr/bin/proot").getAbsolutePath();
|
||||
String tmpDir = new File(filesDir, "usr/tmp").getAbsolutePath();
|
||||
|
||||
if (!FileUtils.isFileExists(filesDir + "/distro" + shell)) {
|
||||
setDefaultShell();
|
||||
}
|
||||
|
||||
if (!FileUtils.isFileExists(filesDir + "/distro" + home)) {
|
||||
FileUtils.createDirectory(filesDir + "/distro" + home);
|
||||
}
|
||||
|
||||
processBuilder.environment().put("PROOT_TMP_DIR", tmpDir);
|
||||
processBuilder.environment().put("HOME", home);
|
||||
processBuilder.environment().put("USER", user);
|
||||
processBuilder.environment().put("TERM", "xterm-256color");
|
||||
processBuilder.environment().put("TMPDIR", "/tmp");
|
||||
processBuilder.environment().put("SHELL", shell);
|
||||
processBuilder.environment().put("DISPLAY", display);
|
||||
processBuilder.environment().put("XDG_RUNTIME_DIR", "/tmp");
|
||||
processBuilder.environment().put("SDL_VIDEODRIVER", "x11");
|
||||
|
||||
String[] prootCommand = {
|
||||
prootPath,
|
||||
"--kill-on-exit",
|
||||
"--link2symlink",
|
||||
"-0",
|
||||
"-r", filesDir + "/distro",
|
||||
"-b", "/dev",
|
||||
"-b", "/proc",
|
||||
"-b", "/sys",
|
||||
"-b", AppConfig.internalDataDirPath + "distro" + home + ":/dev/shm",
|
||||
"-b", "/sdcard",
|
||||
"-b", "/storage",
|
||||
"-b", "/data",
|
||||
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
|
||||
"-w", home,
|
||||
shell,
|
||||
"--login"
|
||||
};
|
||||
|
||||
processBuilder.command(prootCommand);
|
||||
process.set(processBuilder.start());
|
||||
|
||||
resultData data = startProcess((startup.isEmpty() ? "" : startup + " && ") + command, process.get(), callback);
|
||||
|
||||
if (callback != null) callback.onFinished(command, data.log.toString(), data.status);
|
||||
} catch (IOException e) {
|
||||
if (callback != null) callback.onError(command, e);
|
||||
|
||||
addToLogs(command, e.getMessage());
|
||||
} finally {
|
||||
if (progressDialog != null) {
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
progressDialog.reset();
|
||||
progressDialog = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isNewThread) {
|
||||
new Thread(runnable).start();
|
||||
} else {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private resultData startProcess(String command, Process process, Terminal2Callback callback) {
|
||||
resultData data = new resultData();
|
||||
AtomicInteger exitCode = new AtomicInteger();
|
||||
|
||||
int MAX_LOG_SIZE = 200_000; // ~200KB text
|
||||
StringBuilder output = new StringBuilder();
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
writer.write(command);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
Log.d(TAG, line);
|
||||
VectrasStatus.logError(line);
|
||||
output.append(line).append("\n");
|
||||
if (callback != null) callback.onRunning(command, line);
|
||||
|
||||
if (output.length() > MAX_LOG_SIZE) {
|
||||
output.delete(0, output.length() - MAX_LOG_SIZE);
|
||||
}
|
||||
|
||||
if (progressDialog != null) {
|
||||
String finalLine = line;
|
||||
new Handler(Looper.getMainLooper()).post(() -> progressDialog.setText(finalLine));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
exitCode.set(process.waitFor());
|
||||
} catch (InterruptedException e) {
|
||||
exitCode.set(ERROR);
|
||||
}
|
||||
data.status = exitCode.get();
|
||||
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
output.append(e.getMessage());
|
||||
Log.e(TAG, "streamLog: ", e);
|
||||
}
|
||||
|
||||
data.status = exitCode.get();
|
||||
data.log = output;
|
||||
|
||||
addToLogs(command, output.toString());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void addToLogs(String command,String log) {
|
||||
lastLog = log;
|
||||
|
||||
if (!logs.isEmpty()) {
|
||||
logs += "\n\n----------\n\n";
|
||||
}
|
||||
|
||||
logs += "$ " + command + "\n\n";
|
||||
|
||||
logs += log;
|
||||
|
||||
if (logs.contains("\n") && logs.lastIndexOf("\n") > 1000)
|
||||
logs = logs.substring(logs.lastIndexOf("\n") + 1);
|
||||
}
|
||||
|
||||
private class resultData {
|
||||
StringBuilder log;
|
||||
int status;
|
||||
}
|
||||
}
|
||||
10
app/src/main/res/drawable/graphic_eq_24px.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M280,720L280,240L360,240L360,720L280,720ZM440,880L440,80L520,80L520,880L440,880ZM120,560L120,400L200,400L200,560L120,560ZM600,720L600,240L680,240L680,720L600,720ZM760,560L760,400L840,400L840,560L760,560Z"/>
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/graphic_eq_off_96px.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="96dp"
|
||||
android:height="96dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M791,905L520,634L520,880L440,880L440,554L360,474L360,720L280,720L280,394L55,169L112,112L848,848L791,905ZM120,560L120,400L200,400L200,560L120,560ZM520,406L440,326L440,80L520,80L520,406ZM680,566L600,486L600,240L680,240L680,566ZM760,560L760,400L840,400L840,560L760,560Z"/>
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/undo_24px.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M280,760L280,680L564,680Q627,680 673.5,640Q720,600 720,540Q720,480 673.5,440Q627,400 564,400L312,400L416,504L360,560L160,360L360,160L416,216L312,320L564,320Q661,320 730.5,383Q800,446 800,540Q800,634 730.5,697Q661,760 564,760L280,760Z"/>
|
||||
</vector>
|
||||
308
app/src/main/res/layout/activity_equalizer.xml
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
<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.EqualizerActivity">
|
||||
|
||||
<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/equalizer">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/App.CollapsingMaterialToolbar"
|
||||
app:navigationIcon="@drawable/arrow_back_rounded_24px" />
|
||||
|
||||
</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:orientation="vertical"
|
||||
android:paddingTop="100dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_upper_treble"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tv_upper_treble"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/upper_treble"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_upper_treble_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0 dB"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider_upper_treble"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:value="0.0"
|
||||
android:valueFrom="-10"
|
||||
android:valueTo="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_treble"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tv_treble"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/treble"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_treble_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0 dB"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider_treble"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:value="0.0"
|
||||
android:valueFrom="-10"
|
||||
android:valueTo="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_mid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tv_mid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/mid"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_mid_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0 dB"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider_mid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:value="0.0"
|
||||
android:valueFrom="-10"
|
||||
android:valueTo="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_bass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tv_bass"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/bass"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_bass_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0 dB"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider_bass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:value="0.0"
|
||||
android:valueFrom="-10"
|
||||
android:valueTo="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_low_bass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
<TextView
|
||||
android:id="@+id/tv_low_bass"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/low_bass"
|
||||
android:textSize="18sp" />
|
||||
<TextView
|
||||
android:id="@+id/tv_low_bass_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0 dB"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/slider_low_bass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:value="0.0"
|
||||
android:valueFrom="-10"
|
||||
android:valueTo="10" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginVertical="16dp" >
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="16dp"
|
||||
android:src="@drawable/info_24px" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/equalizer_note" />
|
||||
</LinearLayout>
|
||||
|
||||
</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_equalizer"
|
||||
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>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_unsupport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:background="?attr/colorSurfaceContainerLow"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/graphic_eq_off_96px"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/your_device_is_not_supported"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_exit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ok"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -6,9 +6,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.drawerlayout.widget.DrawerLayout 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"
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
@ -28,7 +26,8 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:menu="@menu/home_drawer_menu" />
|
||||
app:menu="@menu/home_drawer_menu"
|
||||
app:itemTextAppearanceActiveBoldEnabled="false" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@
|
|||
android:id="@+id/ln_x11"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:background="@drawable/object_shape_bottom_high"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
|
@ -334,6 +334,43 @@
|
|||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ln_equalizer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:background="@drawable/object_shape_single_high"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:background="@drawable/settings_system_background_icon"
|
||||
android:src="@drawable/graphic_eq_24px" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/equalizer"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/equalizer_settings_note"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
|
|
|
|||
13
app/src/main/res/menu/equalizer_menu.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/undo"
|
||||
android:icon="@drawable/undo_24px"
|
||||
android:title="@string/undo"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@+id/reset"
|
||||
android:icon="@drawable/refresh_24px"
|
||||
android:title="@string/reset"
|
||||
app:showAsAction="always"/>
|
||||
</menu>
|
||||
|
|
@ -609,6 +609,8 @@
|
|||
<string name="need_to_shut_down_all_running_vm_note">Bạn cần tắt tất cả máy ảo đang chạy để thực hiện hành động này.</string>
|
||||
<string name="auto_switch_to_external_mouse">Tự động chuyển sang chuột ngoài</string>
|
||||
<string name="auto_switch_to_external_mouse_note">Tự động chuyển đổi khi kết nối và ngắt chuột rời.</string>
|
||||
<string name="the_necessary_packages_have_been_installed">Các gói cần thiết đã được cài đặt.</string>
|
||||
<string name="an_error_occurred_while_creating_the_virtual_drive">Đã xảy ra lỗi khi tạo ổ đĩa ảo.</string>
|
||||
|
||||
<!--======================TERMUX STRINGS====================-->
|
||||
<string name="application_name" translatable="false">Vterm</string>
|
||||
|
|
@ -768,6 +770,17 @@
|
|||
<string name="blur_effect">Hiệu ứng mờ</string>
|
||||
<string name="blur_effect_note">Làm mờ xung quanh để tăng khả năng tập trung vào một vùng cần được chú ý.</string>
|
||||
<string name="x11_general_setting_note">Bạn cần khởi động lại ứng dụng khi chuyển đổi giữa tích hợp sẵn và ngoài.</string>
|
||||
<string name="equalizer">Bộ chỉnh âm</string>
|
||||
<string name="equalizer_settings_note">Bổng, trung và trầm.</string>
|
||||
<string name="equalizer_note">Bạn có thể cần khởi động lại máy ảo để áp dụng các thay đổi. Hiệu ứng âm thanh có thể chỉ có tác dụng nếu bạn sử dụng các phụ kiện như tai nghe.</string>
|
||||
<string name="use_equalizer">Dùng bộ chỉnh âm</string>
|
||||
<string name="upper_treble">Bổng cao</string>
|
||||
<string name="treble">Bổng</string>
|
||||
<string name="mid">Trung</string>
|
||||
<string name="bass">Trầm</string>
|
||||
<string name="low_bass">Trầm sâu</string>
|
||||
<string name="your_device_is_not_supported">Thiết bị của bạn không được hỗ trợ.</string>
|
||||
<string name="undo">Hoàn tác</string>
|
||||
|
||||
<!-- CPUs -->
|
||||
|
||||
|
|
|
|||
|
|
@ -627,6 +627,19 @@
|
|||
<string name="need_to_shut_down_all_running_vm_note">You need to shut down all running virtual machines to perform this action.</string>
|
||||
<string name="auto_switch_to_external_mouse">Auto switch to external mouse</string>
|
||||
<string name="auto_switch_to_external_mouse_note">Automatically switches when the mouse is connected and disconnected.</string>
|
||||
<string name="the_necessary_packages_have_been_installed">The necessary packages have been installed.</string>
|
||||
<string name="an_error_occurred_while_creating_the_virtual_drive">An error occurred while creating the virtual drive.</string>
|
||||
<string name="equalizer">Equalizer</string>
|
||||
<string name="equalizer_settings_note">Treble, mid and bass.</string>
|
||||
<string name="equalizer_note">You may need to restart the virtual machine for the changes to take effect. Sound effects may be affected if you use accessories such as headphones.</string>
|
||||
<string name="use_equalizer">Use equalizer</string>
|
||||
<string name="upper_treble">Upper treble</string>
|
||||
<string name="treble">Treble</string>
|
||||
<string name="mid">Mid</string>
|
||||
<string name="bass">Bass</string>
|
||||
<string name="low_bass">Low bass</string>
|
||||
<string name="your_device_is_not_supported">Your device is not supported.</string>
|
||||
<string name="undo">Undo</string>
|
||||
|
||||
|
||||
<!--======================TERMUX STRINGS====================-->
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
Welcome to Vectras VM! A virtual machine app for Android based on QEMU that lets you emulate various OSes including: Linux, Windows, Android, macOS and more.
|
||||
|
||||
Minimum System Requirements
|
||||
- Android 6.0 and up.
|
||||
- 3GB RAM (1GB of free RAM).
|
||||
- A good processor.
|
||||
|
||||
Recommended System Requirements
|
||||
- Android 8.1 and up.
|
||||
- 8GB RAM (3GB of free RAM).
|
||||
- CPU and Android OS support 64-bit.
|
||||
- Snapdragon 855 CPU or better.
|
||||
- Integrated or removable cooling system (if running operating systems from 2010 to present).
|
||||
|
||||
Tips: If the OS you are trying to emulate crashes, try using an older version.
|
||||
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
|
@ -1 +0,0 @@
|
|||
It's a Virtual Machine App for Android Which is Based on QEMU
|
||||
|
|
@ -11,14 +11,14 @@ coreKtx = "1.19.0"
|
|||
documentfile = "1.1.0"
|
||||
drawerlayout = "1.2.0"
|
||||
espressoCore = "3.7.0"
|
||||
firebaseBom = "34.14.1"
|
||||
firebaseBom = "34.15.0"
|
||||
firebaseCrashlyticsGradle = "3.0.7"
|
||||
firebaseMessaging = "25.0.2"
|
||||
firebaseMessaging = "25.1.0"
|
||||
glide = "5.0.7"
|
||||
googleFirebase = "firebase-analytics"
|
||||
googleFirebaseCrashlytics = "3.0.7"
|
||||
googleGmsGoogleServices = "4.4.4"
|
||||
googleServices = "4.4.4"
|
||||
googleGmsGoogleServices = "4.5.0"
|
||||
googleServices = "4.5.0"
|
||||
gradle = "9.2.1"
|
||||
gradleToolchainsFoojayResolverConvention = "1.0.0"
|
||||
gson = "2.14.0"
|
||||
|
|
|
|||
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,7 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=553c78f50dafcd54d65b9a444649057857469edf836431389695608536d6b746
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
||||
distributionSha256Sum=bbaeb2fef8710818cf0e261201dab964c572f92b942812df0c3620d62a529a01
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
|
|
|
|||
4
gradlew
vendored
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
# gradlew start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
# ksh gradlew
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
|
|
|
|||
4
gradlew.bat
vendored
|
|
@ -19,7 +19,7 @@
|
|||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem gradlew startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2
|
|||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
@rem Execute gradlew
|
||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||
@rem which allows us to clear the local environment before executing the java command
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||
|
|
|
|||
BIN
web/1024.png
|
Before Width: | Height: | Size: 129 KiB |
|
|
@ -1,18 +0,0 @@
|
|||
Add this to your HTML <head>:
|
||||
|
||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
|
||||
Add this to your app's manifest.json:
|
||||
|
||||
...
|
||||
{
|
||||
"icons": [
|
||||
{ "src": "/favicon.ico", "type": "image/x-icon", "sizes": "16x16 32x32" },
|
||||
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
|
||||
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" },
|
||||
{ "src": "/icon-192-maskable.png", "type": "image/png", "sizes": "192x192", "purpose": "maskable" },
|
||||
{ "src": "/icon-512-maskable.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" }
|
||||
]
|
||||
}
|
||||
...
|
||||
|
Before Width: | Height: | Size: 9.3 KiB |
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<meta content='#151e25' name='theme-color' />
|
||||
<meta content='#151e25' name='msapplication-navbutton-color' />
|
||||
<meta content='#151e25' name='apple-mobile-web-app-status-bar-style' />
|
||||
<meta content='true' name='apple-mobile-web-app-capable' />
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="Home">
|
||||
<meta name="keywords" content="Windows,Linux,Emulator,Discord">
|
||||
<meta name="author" content="Nguyen Bao An Bui">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta property="og:image" content="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2FInShot_20230228_181958299.jpg?alt=media&token=ea22e382-f35a-43ce-be02-799358aaea2b">
|
||||
<title>Just a moment... Home</title>
|
||||
<link rel="icon" type="image/x-icon" href="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2F1677640749718.png?alt=media&token=3ba289db-3a05-4ea5-b318-42ef5e8cf613">
|
||||
<link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
|
||||
<link rel="stylesheet" href="https://nguyenbaoanbui-86deb.web.app/style/style.css">
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Just a moment...</h1>
|
||||
|
||||
<script>
|
||||
document.location.href="https://anbui.ovh/vectrasvm";
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -5,11 +5,11 @@
|
|||
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
|
||||
"Message": "<h2>4.3.0</h2>\nBugs fixed.",
|
||||
"cancellable": true,
|
||||
"versionCodeBeta":"134",
|
||||
"versionNameBeta":"4.3.0",
|
||||
"versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.0,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7,4.2.8,4.2.9,4.3.0",
|
||||
"versionCodeBeta":"137",
|
||||
"versionNameBeta":"4.3.3",
|
||||
"versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7,4.2.8,4.2.9,4.3.0,4.3.1,4.3.2,4.3.3",
|
||||
"sizeBeta": "45 MB",
|
||||
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
|
||||
"MessageBeta": "<h2>4.3.0</h2>Bugs fixed.",
|
||||
"MessageBeta": "<h2>4.3.3</h2>Bugs fixed.",
|
||||
"cancellableBeta": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1541,6 +1541,26 @@
|
|||
"vecid": "windows10mobilecvbi",
|
||||
"id": "99672"
|
||||
},
|
||||
{
|
||||
"rom_name": "Windows 10 S 1709 ARM64 build 16299",
|
||||
"rom_icon": "https://vuetiwuvbyxywfukompp.supabase.co/storage/v1/object/public/getmyos/v1/files/2018/09/17/windows-logo_1_926ed76111646acbbe332bc5af0cf2ce.png",
|
||||
"rom_url": "https://youtu.be/2csyaU2w8dk",
|
||||
"rom_path": "Windows 10 S ARM64 build 16299.cvbi",
|
||||
"rom_avail": true,
|
||||
"gui": true,
|
||||
"rom_size": "Fall Creators Update",
|
||||
"rom_arch": "ARM64",
|
||||
"rom_kernel": "windows",
|
||||
"rom_extra": "",
|
||||
"final_rom_file_name": "",
|
||||
"desc": "This Rom is from Nguyen Bao An Bui. You can get it on An Bui app: https://play.google.com/store/apps/details?id=com.anbui.app\n\nWindows 10 is a major release of the Windows NT operating system developed by Microsoft. The successor to Windows 8.1, it was released to manufacturing on July 15, 2015, became generally available on July 29, 2015, and was a free upgrade to users of Windows 7, 8, and 8.1. Its server counterparts are Windows Server 2016, 2019, and 2022. It was succeeded by Windows 11 in October 2021.",
|
||||
"file_size": "16 GB",
|
||||
"containsAds": true,
|
||||
"creator": "Nguyen Bao An Bui",
|
||||
"verified": true,
|
||||
"vecid": "windows10sarm64build16299cvbi",
|
||||
"id": "99627"
|
||||
},
|
||||
{
|
||||
"rom_name": "Windows 11 21H2",
|
||||
"rom_icon": "https://www.getmyos.com/app_public/files/t/1/2021/06/windows_11_logo_by_getmyos.png",
|
||||
|
|
|
|||
BIN
web/favicon.ico
|
Before Width: | Height: | Size: 5.1 KiB |
30
web/how.html
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<meta content='#151e25' name='theme-color' />
|
||||
<meta content='#151e25' name='msapplication-navbutton-color' />
|
||||
<meta content='#151e25' name='apple-mobile-web-app-status-bar-style' />
|
||||
<meta content='true' name='apple-mobile-web-app-capable' />
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="Home">
|
||||
<meta name="keywords" content="Windows,Linux,Emulator,Discord">
|
||||
<meta name="author" content="Nguyen Bao An Bui">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta property="og:image" content="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2FInShot_20230228_181958299.jpg?alt=media&token=ea22e382-f35a-43ce-be02-799358aaea2b">
|
||||
<title>Just a moment... Home</title>
|
||||
<link rel="icon" type="image/x-icon" href="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2F1677640749718.png?alt=media&token=3ba289db-3a05-4ea5-b318-42ef5e8cf613">
|
||||
<link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
|
||||
<link rel="stylesheet" href="https://nguyenbaoanbui-86deb.web.app/style/style.css">
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Just a moment...</h1>
|
||||
|
||||
<script>
|
||||
document.location.href="https://anbui.ovh/vectrasvm";
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 9.8 KiB |
BIN
web/icon-192.png
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 35 KiB |
BIN
web/icon-512.png
|
Before Width: | Height: | Size: 42 KiB |
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<meta content='#151e25' name='theme-color' />
|
||||
<meta content='#151e25' name='msapplication-navbutton-color' />
|
||||
<meta content='#151e25' name='apple-mobile-web-app-status-bar-style' />
|
||||
<meta content='true' name='apple-mobile-web-app-capable' />
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="Home">
|
||||
<meta name="keywords" content="Windows,Linux,Emulator,Discord">
|
||||
<meta name="author" content="Nguyen Bao An Bui">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta property="og:image" content="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2FInShot_20230228_181958299.jpg?alt=media&token=ea22e382-f35a-43ce-be02-799358aaea2b">
|
||||
<title>Just a moment... Home</title>
|
||||
<link rel="icon" type="image/x-icon" href="https://firebasestorage.googleapis.com/v0/b/baoanbui-ac174.appspot.com/o/Logo%2F1677640749718.png?alt=media&token=3ba289db-3a05-4ea5-b318-42ef5e8cf613">
|
||||
<link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
|
||||
<link rel="stylesheet" href="https://nguyenbaoanbui-86deb.web.app/style/style.css">
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Just a moment...</h1>
|
||||
|
||||
<script>
|
||||
document.location.href="https://anbui.ovh/vectrasvm";
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
web/logo.png
|
Before Width: | Height: | Size: 98 KiB |