From 3990bbb4c86d40cede6f3fd1b7443aeb20004b95 Mon Sep 17 00:00:00 2001
From: An Bui <91354810+AnBui2004@users.noreply.github.com>
Date: Thu, 9 Jul 2026 23:38:17 +0700
Subject: [PATCH] 4.3.3
- Fixed the issue of being unable to insert or change optical discs, floppy drives, and memory cards when filenames contained spaces.
- Added equalizer.
- Bubbles on the built-in VNC screen will automatically fade when there is no interaction.
- The default setting for automatically switching to external mouse mode on the built-in VNC screen is now off.
---
app/build.gradle | 4 +-
app/src/main/AndroidManifest.xml | 5 +
.../com/vectras/qemu/MainSettingsManager.java | 2 +-
.../com/vectras/qemu/MainVNCActivity.java | 2 +-
.../com/vectras/vm/manager/QmpSender.java | 2 +-
.../vm/settings/EqualizerActivity.java | 195 +++++++++++
.../vm/settings/Settings2Activity.java | 2 +
.../vectras/vm/sound/AudioSettingsData.java | 62 ++++
.../com/vectras/vm/sound/SoundEffect.java | 118 +++++++
.../com/vectras/vm/sound/StreamAudio.java | 65 ++++
.../com/vectras/vm/view/DynamicBubble.java | 7 +
.../java/com/vectras/vm/x11/X11Activity.java | 2 +-
app/src/main/res/drawable/graphic_eq_24px.xml | 10 +
.../main/res/drawable/graphic_eq_off_96px.xml | 10 +
app/src/main/res/drawable/undo_24px.xml | 11 +
.../main/res/layout/activity_equalizer.xml | 308 ++++++++++++++++++
app/src/main/res/layout/activity_main.xml | 7 +-
.../main/res/layout/activity_settings2.xml | 39 ++-
app/src/main/res/menu/equalizer_menu.xml | 13 +
app/src/main/res/values-vi/strings.xml | 11 +
app/src/main/res/values/strings.xml | 11 +
web/data/UpdateConfig.json | 8 +-
22 files changed, 879 insertions(+), 15 deletions(-)
create mode 100644 app/src/main/java/com/vectras/vm/settings/EqualizerActivity.java
create mode 100644 app/src/main/java/com/vectras/vm/sound/AudioSettingsData.java
create mode 100644 app/src/main/java/com/vectras/vm/sound/SoundEffect.java
create mode 100644 app/src/main/res/drawable/graphic_eq_24px.xml
create mode 100644 app/src/main/res/drawable/graphic_eq_off_96px.xml
create mode 100644 app/src/main/res/drawable/undo_24px.xml
create mode 100644 app/src/main/res/layout/activity_equalizer.xml
create mode 100644 app/src/main/res/menu/equalizer_menu.xml
diff --git a/app/build.gradle b/app/build.gradle
index 03201c9..4a074e8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,8 +12,8 @@ android {
applicationId "com.vectras.vm"
minSdk minApi
targetSdk targetApi
- versionCode 136
- versionName "4.3.2"
+ versionCode 137
+ versionName "4.3.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7a7b5d2..7c09edb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -299,6 +299,11 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/vectras/qemu/MainSettingsManager.java b/app/src/main/java/com/vectras/qemu/MainSettingsManager.java
index c9a51f4..59d51bc 100644
--- a/app/src/main/java/com/vectras/qemu/MainSettingsManager.java
+++ b/app/src/main/java/com/vectras/qemu/MainSettingsManager.java
@@ -1341,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);
}
}
diff --git a/app/src/main/java/com/vectras/qemu/MainVNCActivity.java b/app/src/main/java/com/vectras/qemu/MainVNCActivity.java
index ccb6295..617ea55 100644
--- a/app/src/main/java/com/vectras/qemu/MainVNCActivity.java
+++ b/app/src/main/java/com/vectras/qemu/MainVNCActivity.java
@@ -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();
}
diff --git a/app/src/main/java/com/vectras/vm/manager/QmpSender.java b/app/src/main/java/com/vectras/vm/manager/QmpSender.java
index 861cc89..76a8e5e 100644
--- a/app/src/main/java/com/vectras/vm/manager/QmpSender.java
+++ b/app/src/main/java/com/vectras/vm/manager/QmpSender.java
@@ -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) {
diff --git a/app/src/main/java/com/vectras/vm/settings/EqualizerActivity.java b/app/src/main/java/com/vectras/vm/settings/EqualizerActivity.java
new file mode 100644
index 0000000..7fe1328
--- /dev/null
+++ b/app/src/main/java/com/vectras/vm/settings/EqualizerActivity.java
@@ -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";
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/vectras/vm/settings/Settings2Activity.java b/app/src/main/java/com/vectras/vm/settings/Settings2Activity.java
index 9dd2bf4..30bb1d3 100644
--- a/app/src/main/java/com/vectras/vm/settings/Settings2Activity.java
+++ b/app/src/main/java/com/vectras/vm/settings/Settings2Activity.java
@@ -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)));
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/vectras/vm/sound/AudioSettingsData.java b/app/src/main/java/com/vectras/vm/sound/AudioSettingsData.java
new file mode 100644
index 0000000..d7a53f1
--- /dev/null
+++ b/app/src/main/java/com/vectras/vm/sound/AudioSettingsData.java
@@ -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);
+ }
+}
diff --git a/app/src/main/java/com/vectras/vm/sound/SoundEffect.java b/app/src/main/java/com/vectras/vm/sound/SoundEffect.java
new file mode 100644
index 0000000..2eaec7b
--- /dev/null
+++ b/app/src/main/java/com/vectras/vm/sound/SoundEffect.java
@@ -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;
+ }
+}
diff --git a/app/src/main/java/com/vectras/vm/sound/StreamAudio.java b/app/src/main/java/com/vectras/vm/sound/StreamAudio.java
index 756ff72..f5a4599 100644
--- a/app/src/main/java/com/vectras/vm/sound/StreamAudio.java
+++ b/app/src/main/java/com/vectras/vm/sound/StreamAudio.java
@@ -5,6 +5,7 @@ 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;
@@ -19,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;
@@ -56,6 +58,10 @@ public class StreamAudio {
sampleRate = 48000;
}
+ public void release() {
+ isPlay = false;
+ releaseSoundEffect();
+ }
public void streamFromFile() {
if (isPlay) return;
@@ -102,6 +108,8 @@ public class StreamAudio {
.setTransferMode(AudioTrack.MODE_STREAM)
.build();
+ applyEffect(audioTrack);
+
audioTrack.play();
if (cross != null && !cross.isDestroyed && cross.isPlaying()) cross.stop();
@@ -135,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();
diff --git a/app/src/main/java/com/vectras/vm/view/DynamicBubble.java b/app/src/main/java/com/vectras/vm/view/DynamicBubble.java
index 285d470..8836331 100644
--- a/app/src/main/java/com/vectras/vm/view/DynamicBubble.java
+++ b/app/src/main/java/com/vectras/vm/view/DynamicBubble.java
@@ -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 {
diff --git a/app/src/main/java/com/vectras/vm/x11/X11Activity.java b/app/src/main/java/com/vectras/vm/x11/X11Activity.java
index 72803dd..18a73f3 100644
--- a/app/src/main/java/com/vectras/vm/x11/X11Activity.java
+++ b/app/src/main/java/com/vectras/vm/x11/X11Activity.java
@@ -752,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();
}
diff --git a/app/src/main/res/drawable/graphic_eq_24px.xml b/app/src/main/res/drawable/graphic_eq_24px.xml
new file mode 100644
index 0000000..ee498e8
--- /dev/null
+++ b/app/src/main/res/drawable/graphic_eq_24px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/graphic_eq_off_96px.xml b/app/src/main/res/drawable/graphic_eq_off_96px.xml
new file mode 100644
index 0000000..d532fad
--- /dev/null
+++ b/app/src/main/res/drawable/graphic_eq_off_96px.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/undo_24px.xml b/app/src/main/res/drawable/undo_24px.xml
new file mode 100644
index 0000000..a3f745b
--- /dev/null
+++ b/app/src/main/res/drawable/undo_24px.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_equalizer.xml b/app/src/main/res/layout/activity_equalizer.xml
new file mode 100644
index 0000000..6f51acb
--- /dev/null
+++ b/app/src/main/res/layout/activity_equalizer.xml
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index cc07d5e..7d5b74d 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -6,9 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ app:menu="@menu/home_drawer_menu"
+ app:itemTextAppearanceActiveBoldEnabled="false" />
diff --git a/app/src/main/res/layout/activity_settings2.xml b/app/src/main/res/layout/activity_settings2.xml
index c4a2769..98587cc 100644
--- a/app/src/main/res/layout/activity_settings2.xml
+++ b/app/src/main/res/layout/activity_settings2.xml
@@ -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" />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/equalizer_menu.xml b/app/src/main/res/menu/equalizer_menu.xml
new file mode 100644
index 0000000..00f3199
--- /dev/null
+++ b/app/src/main/res/menu/equalizer_menu.xml
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 5365e25..a9818ac 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -770,6 +770,17 @@
Hiệu ứng mờ
Làm mờ xung quanh để tăng khả năng tập trung vào một vùng cần được chú ý.
Bạn cần khởi động lại ứng dụng khi chuyển đổi giữa tích hợp sẵn và ngoài.
+ Bộ chỉnh âm
+ Bổng, trung và trầm.
+ 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.
+ Dùng bộ chỉnh âm
+ Bổng cao
+ Bổng
+ Trung
+ Trầm
+ Trầm sâu
+ Thiết bị của bạn không được hỗ trợ.
+ Hoàn tác
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1bf76eb..f8956c3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -629,6 +629,17 @@
Automatically switches when the mouse is connected and disconnected.
The necessary packages have been installed.
An error occurred while creating the virtual drive.
+ Equalizer
+ Treble, mid and bass.
+ 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.
+ Use equalizer
+ Upper treble
+ Treble
+ Mid
+ Bass
+ Low bass
+ Your device is not supported.
+ Undo
diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json
index 63d593c..b814b06 100644
--- a/web/data/UpdateConfig.json
+++ b/web/data/UpdateConfig.json
@@ -5,11 +5,11 @@
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
"Message": "4.3.0
\nBugs fixed.",
"cancellable": true,
- "versionCodeBeta":"136",
- "versionNameBeta":"4.3.2",
- "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",
+ "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": "4.3.2
Bugs fixed.",
+ "MessageBeta": "4.3.3
Bugs fixed.",
"cancellableBeta": true
}