Merge pull request #409 from AnBui2004/master

v2.9.5.12-3dfx
This commit is contained in:
An Bui 2025-10-05 19:52:58 +07:00 committed by GitHub
commit 94a3ff2dea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 522 additions and 467 deletions

View file

@ -11,7 +11,7 @@ android {
minSdk minApi
targetSdk targetApi
versionCode 21
versionName "v2.9.5.11-3dfx"
versionName "v2.9.5.12-3dfx"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
@ -72,7 +72,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.7.1'
implementation 'com.google.android.material:material:1.14.0-alpha04'
implementation 'com.google.android.material:material:1.14.0-alpha05'
implementation "androidx.annotation:annotation:1.9.1"
implementation "androidx.core:core:1.17.0"
implementation "androidx.drawerlayout:drawerlayout:1.2.0"
@ -90,7 +90,7 @@ dependencies {
implementation 'com.google.guava:guava:33.5.0-jre'
implementation 'com.google.code.gson:gson:2.13.2'
implementation 'com.squareup.okhttp3:okhttp:5.1.0'
implementation "androidx.window:window:1.4.0"
implementation "androidx.window:window:1.5.0"
implementation "commons-io:commons-io:2.20.0"
implementation 'org.zeroturnaround:zt-zip:1.17'
implementation 'com.airbnb.android:lottie:6.6.9'

View file

@ -269,6 +269,16 @@
<action android:name="com.vectras.vm.x11.CHANGE_PREFERENCE" />
</intent-filter>
</receiver>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
<!--
This (or rather, value 2.1 or higher) is needed to make the Samsung Galaxy S8 mark the
app with "This app is optimized to run in full screen."

View file

@ -10,8 +10,11 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import androidx.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
@ -28,13 +31,19 @@ import com.vectras.vm.SplashActivity;
import com.vectras.vm.VectrasApp;
import java.util.Locale;
import java.util.Objects;
public class MainSettingsManager extends AppCompatActivity
implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
public static final String TAG = "MainSettingsManager";
public static MainSettingsManager activity;
private static Handler mHandler;
public static SharedPreferences sp;
public static int goToXML = -1;
public static boolean isAllowFirstChangeSubtitle = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -47,7 +56,6 @@ public class MainSettingsManager extends AppCompatActivity
sp = PreferenceManager.getDefaultSharedPreferences(activity);
PreferenceFragmentCompat preference = new MainPreferencesFragment();
Intent intent = getIntent();
// add preference settings
getSupportFragmentManager().beginTransaction()
@ -55,18 +63,33 @@ public class MainSettingsManager extends AppCompatActivity
.commit();
// toolbar
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
Toolbar mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout);
if (getIntent().hasExtra("goto")) {
isAllowFirstChangeSubtitle = false;
if (Objects.equals(getIntent().getStringExtra("goto"), "qemu")) {
goToXML = R.xml.qemu;
collapsingToolbarLayout.setSubtitle(getString(R.string.qemu));
}
}
}
@Override
public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, Preference pref) {
// Instantiate the new Fragment
final Bundle bundle = pref.getExtras();
final Fragment fragment = Fragment.instantiate(this, pref.getFragment(), bundle);
fragment.setTargetFragment(caller, 0);
assert pref.getFragment() != null;
Fragment fragment = getSupportFragmentManager()
.getFragmentFactory()
.instantiate(getClassLoader(), pref.getFragment());
fragment.setArguments(bundle);
// fragment.setTargetFragment(caller, 0);
// Replace the existing Fragment with the new Fragment
getSupportFragmentManager().beginTransaction()
@ -94,11 +117,13 @@ public class MainSettingsManager extends AppCompatActivity
@Override
public void onResume() {
super.onResume();
CollapsingToolbarLayout collapsingToolbarLayout =
requireActivity().findViewById(R.id.collapsingToolbarLayout);
if (MainSettingsManager.isAllowFirstChangeSubtitle) {
CollapsingToolbarLayout collapsingToolbarLayout =
requireActivity().findViewById(R.id.collapsingToolbarLayout);
if (collapsingToolbarLayout != null) {
collapsingToolbarLayout.setSubtitle(getString(R.string.general));
if (collapsingToolbarLayout != null) {
collapsingToolbarLayout.setSubtitle(getString(R.string.general));
}
}
}
@ -112,14 +137,12 @@ public class MainSettingsManager extends AppCompatActivity
@Override
public void onCreatePreferences(Bundle bundle, String root_key) {
// Load the Preferences from the XML file
setPreferencesFromResource(R.xml.headers_preference, root_key);
setPreferencesFromResource(MainSettingsManager.goToXML == -1 ? R.xml.headers_preference : MainSettingsManager.goToXML, root_key);
MainSettingsManager.goToXML = -1;
}
@Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
if (pref.getKey().equals("app")) {
}
public boolean onPreferenceChange(@NonNull Preference pref, Object newValue) {
return true;
}
@ -162,26 +185,26 @@ public class MainSettingsManager extends AppCompatActivity
languagePref.setOnPreferenceChangeListener(this);
}
SwitchPreferenceCompat switchPreferenceCompat = findPreference("updateVersionPrompt");
assert switchPreferenceCompat != null;
SwitchPreferenceCompat switchJoinBetaChannel = findPreference("checkforupdatesfromthebetachannel");
assert switchJoinBetaChannel != null;
if (!switchPreferenceCompat.isChecked()) {
switchJoinBetaChannel.setEnabled(false);
}
switchPreferenceCompat.setOnPreferenceChangeListener((preference, newValue) -> {
if (!(Boolean) newValue) {
if (switchJoinBetaChannel.isEnabled())
switchJoinBetaChannel.setEnabled(false);
} else {
if (!switchJoinBetaChannel.isEnabled())
switchJoinBetaChannel.setEnabled(true);
}
return true;
});
// SwitchPreferenceCompat switchPreferenceCompat = findPreference("updateVersionPrompt");
// assert switchPreferenceCompat != null;
// SwitchPreferenceCompat switchJoinBetaChannel = findPreference("checkforupdatesfromthebetachannel");
// assert switchJoinBetaChannel != null;
//
// if (!switchPreferenceCompat.isChecked()) {
// switchJoinBetaChannel.setEnabled(false);
// }
//
// switchPreferenceCompat.setOnPreferenceChangeListener((preference, newValue) -> {
// if (!(Boolean) newValue) {
// if (switchJoinBetaChannel.isEnabled())
// switchJoinBetaChannel.setEnabled(false);
// } else {
// if (!switchJoinBetaChannel.isEnabled())
// switchJoinBetaChannel.setEnabled(true);
//
// }
// return true;
// });
}
@ -268,7 +291,7 @@ public class MainSettingsManager extends AppCompatActivity
}
@Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
public boolean onPreferenceChange(@NonNull Preference pref, Object newValue) {
return true;
}
@ -284,9 +307,9 @@ public class MainSettingsManager extends AppCompatActivity
//Preference prefIfType = findPreference("ifType");
//if (getArch(activity).equals("ARM64"))
//if (prefIfType != null) {
//prefIfType.setVisible(false);
//}
//if (prefIfType != null) {
//prefIfType.setVisible(false);
//}
Preference pref = findPreference("vmArch");
if (pref != null) {
@ -359,12 +382,9 @@ public class MainSettingsManager extends AppCompatActivity
}
private void onArch() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
activity.finish();
startActivity(new Intent(activity, SplashActivity.class));
}
mHandler.postDelayed(() -> {
activity.finish();
startActivity(new Intent(activity, SplashActivity.class));
}, 300);
}
@ -401,7 +421,7 @@ public class MainSettingsManager extends AppCompatActivity
}
@Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
public boolean onPreferenceChange(@NonNull Preference pref, Object newValue) {
return true;
}
@ -442,10 +462,7 @@ public class MainSettingsManager extends AppCompatActivity
}
@Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
if (pref.getKey().equals("app")) {
}
public boolean onPreferenceChange(@NonNull Preference pref, Object newValue) {
return true;
}
@ -490,9 +507,8 @@ public class MainSettingsManager extends AppCompatActivity
public static int getOrientationSetting(Activity activity) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
int orientation = prefs.getInt("orientation", 0);
// UIUtils.log("Getting First time: " + firstTime);
return orientation;
return prefs.getInt("orientation", 0);
}
public static void setOrientationSetting(Activity activity, int orientation) {
@ -571,42 +587,39 @@ public class MainSettingsManager extends AppCompatActivity
public static String getLastDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("lastDir", null);
return imagesDir;
return prefs.getString("lastDir", null);
}
public static void setLastDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("lastDir", imagesPath);
edit.commit();
edit.apply();
}
public static String getImagesDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("imagesDir", null);
return imagesDir;
return prefs.getString("imagesDir", null);
}
public static void setImagesDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("imagesDir", imagesPath);
edit.commit();
edit.apply();
}
public static String getExportDir(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String imagesDir = prefs.getString("exportDir", null);
return imagesDir;
return prefs.getString("exportDir", null);
}
public static void setExportDir(Context context, String imagesPath) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("exportDir", imagesPath);
edit.commit();
edit.apply();
}
@ -626,28 +639,26 @@ public class MainSettingsManager extends AppCompatActivity
public static int getExitCode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int exitCode = prefs.getInt("exitCode", 1);
return exitCode;
return prefs.getInt("exitCode", 1);
}
public static void setExitCode(Context context, int exitCode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("exitCode", exitCode);
edit.commit();
edit.apply();
}
public static String getControlMode(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String controlMode = prefs.getString("controlMode", "D");
return controlMode;
return prefs.getString("controlMode", "D");
}
public static void setControlMode(Context context, String controlMode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("controlMode", controlMode);
edit.commit();
edit.apply();
}
@ -655,7 +666,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("modeNight", nightMode);
edit.commit();
edit.apply();
}
public static Boolean getModeNight(Context context) {
@ -812,29 +823,30 @@ public class MainSettingsManager extends AppCompatActivity
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(activity.getClass().getPackage().getName(),
pInfo = activity.getPackageManager().getPackageInfo(Objects.requireNonNull(activity.getClass().getPackage()).getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "isFirstLaunch", e);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
boolean firstTime = prefs.getBoolean("firstTime" + pInfo.versionName, true);
return firstTime;
assert pInfo != null;
return prefs.getBoolean("firstTime" + pInfo.versionName, true);
}
public static void setFirstLaunch(Activity activity) {
PackageInfo pInfo = null;
try {
pInfo = activity.getPackageManager().getPackageInfo(activity.getClass().getPackage().getName(),
pInfo = activity.getPackageManager().getPackageInfo(Objects.requireNonNull(activity.getClass().getPackage()).getName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "setFirstLaunch", e);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor edit = prefs.edit();
assert pInfo != null;
edit.putBoolean("firstTime" + pInfo.versionName, false);
edit.commit();
edit.apply();
}
@ -870,7 +882,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("setUpWithManualSetupBefore", _boolean);
edit.commit();
edit.apply();
}
public static Boolean getsetUpWithManualSetupBefore(Context context) {
@ -882,7 +894,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("SelectedMirror", _int);
edit.commit();
edit.apply();
}
public static int getSelectedMirror(Context context) {
@ -894,7 +906,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("dontShowAgainJoinBetaUpdateChannelDialog", _boolean);
edit.commit();
edit.apply();
}
public static Boolean getDontShowAgainJoinBetaUpdateChannelDialog(Context context) {
@ -906,7 +918,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("useDefaultBios", _boolean);
edit.commit();
edit.apply();
}
public static Boolean getuseDefaultBios(Context context) {
@ -918,7 +930,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("useUEFI", _boolean);
edit.commit();
edit.apply();
}
public static Boolean getuseUEFI(Context context) {
@ -930,7 +942,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putString("skipVersion", version);
edit.commit();
edit.apply();
}
public static String getSkipVersion(Context context) {
@ -942,7 +954,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt("vncScaleMode", mode);
edit.commit();
edit.apply();
}
public static int getVNCScaleMode(Context context) {
@ -954,7 +966,7 @@ public class MainSettingsManager extends AppCompatActivity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("forceRefeshVNCDisplay", _boolean);
edit.commit();
edit.apply();
}
public static Boolean getForceRefeshVNCDisplay(Context context) {

View file

@ -73,6 +73,7 @@ public class AppConfig {
public static String downloadsFolder = maindirpath + "Downloads/";
public static String romsdatajson = maindirpath + "roms-data.json";
public static String vmFolder = maindirpath + "roms/";
public static String importedDriveFolder = maindirpath + "drive/";
public static String pendingCommand = "";
public static String neededPkgs = "aria2 tar dwm xfce4-terminal libslirp libslirp-dev pulseaudio-dev glib-dev pixman-dev zlib-dev spice-dev" +

View file

@ -56,8 +56,8 @@ public class CustomRomActivity extends AppCompatActivity {
boolean iseditparams = false;
public String previousName = "";
public boolean addromnowdone = false;
public static String vmID = VMManager.idGenerator();
public int port = VMManager.startRandomPort();
private String vmID = VMManager.idGenerator();
private int port = VMManager.startRandomPort();
private boolean created = false;
private String thumbnailPath = "";
private final Timer _timer = new Timer();
@ -114,6 +114,7 @@ public class CustomRomActivity extends AppCompatActivity {
binding.driveField.setEndIconOnClickListener(v -> {
if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) {
CreateImageDialogFragment dialogFragment = new CreateImageDialogFragment();
dialogFragment.folder = AppConfig.vmFolder + vmID + "/";
dialogFragment.customRom = true;
dialogFragment.filename = Objects.requireNonNull(binding.title.getText()).toString();
dialogFragment.drive = binding.drive;
@ -244,7 +245,7 @@ public class CustomRomActivity extends AppCompatActivity {
thumbnailPath = current.itemIcon;
vmID = getIntent().getStringExtra("VMID");
if (vmID != null && vmID.isEmpty()) {
if (vmID == null || vmID.isEmpty()) {
vmID = VMManager.idGenerator();
}

View file

@ -30,7 +30,7 @@ public class CreateImageDialogFragment extends DialogFragment {
public boolean customRom = false;
public String folder = AppConfig.vmFolder + CustomRomActivity.vmID + "/";
public String folder = AppConfig.maindirpath;
public String filename = "disk";
public TextInputEditText drive;
public TextInputLayout driveLayout;

View file

@ -16,6 +16,7 @@ import androidx.appcompat.app.AppCompatActivity;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.databinding.ActivitySetArchBinding;
import com.vectras.vm.home.HomeActivity;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vm.utils.UIUtils;
@ -50,9 +51,7 @@ public class SetArchActivity extends AppCompatActivity implements View.OnClickLi
binding.toolbar.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.roms_store) {
Intent intent = new Intent(this, RomsManagerActivity.class);
startActivity(intent);
HomeActivity.isOpenRomStore = true;
finish();
return true;
}

View file

@ -1,32 +1,28 @@
package com.vectras.vm.home;
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static android.content.Intent.ACTION_VIEW;
import static android.os.Build.VERSION.SDK_INT;
import static com.vectras.vm.VectrasApp.getApp;
import static com.vectras.vm.utils.UIUtils.UIAlert;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.DocumentsContract;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.activity.OnBackPressedCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
@ -39,6 +35,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.Gson;
import com.termux.app.TermuxActivity;
import com.vectras.qemu.Config;
@ -46,7 +43,6 @@ import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.AboutActivity;
import com.vectras.vm.AppConfig;
import com.vectras.vm.CustomRomActivity;
import com.vectras.vm.DataExplorerActivity;
import com.vectras.vm.Minitools;
import com.vectras.vm.R;
import com.vectras.vm.RequestNetwork;
@ -81,24 +77,23 @@ import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
public class HomeActivity extends AppCompatActivity implements RomStoreFragment.RomStoreCallToHomeListener, VmsFragment.VmsCallToHomeListener {
public static String curRomName;
private final String TAG = "HomeActivity";
public static boolean isActivate = false;
public static boolean isOpenRomStore = false;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
ActivityHomeBinding binding;
ActivityHomeContentBinding bindingContent;
private RomStoreHomeAdapterSearch adapterRomStoreSearch;
@ -210,13 +205,10 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
bindingContent.searchbar.setEnabled(false);
}
if (selectedFragment != null) {
getSupportFragmentManager().beginTransaction()
.replace(bindingContent.containerView.getId(), selectedFragment)
.commit();
return true;
}
return false;
getSupportFragmentManager().beginTransaction()
.replace(bindingContent.containerView.getId(), selectedFragment)
.commit();
return true;
});
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@ -308,178 +300,76 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
DisplaySystem.reLaunchVNC(this);
PendingCommand.runNow(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent ReturnedIntent) {
super.onActivityResult(requestCode, resultCode, ReturnedIntent);
if (requestCode == 1004 && resultCode == RESULT_OK) {
Uri content_describer = ReturnedIntent.getData();
File selectedFilePath = new File(getPath(content_describer));
ProgressBar loading = findViewById(R.id.loading);
if (selectedFilePath.toString().endsWith(".iso")) {
loading.setVisibility(View.VISIBLE);
new Thread(() -> {
FileInputStream File;
try {
assert content_describer != null;
File = (FileInputStream) getContentResolver().openInputStream(content_describer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
try {
try {
try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/drive.iso")) {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while (true) {
assert File != null;
if (!((len = File.read(buf)) > 0)) break;
out.write(buf, 0, len);
}
}
} finally {
Runnable runnable = () -> loading.setVisibility(View.GONE);
runOnUiThread(runnable);
assert File != null;
File.close();
}
} catch (IOException e) {
Runnable runnable = () -> {
loading.setVisibility(View.GONE);
UIAlert(this, e.toString(), "error");
};
runOnUiThread(runnable);
}
}).start();
} else
UIAlert(this, "please select iso file", "INVALID FILE");
} else if (requestCode == 1005 && resultCode == RESULT_OK) {
Uri content_describer = ReturnedIntent.getData();
ProgressBar loading = findViewById(R.id.loading);
loading.setVisibility(View.VISIBLE);
new Thread(() -> {
FileInputStream File;
try {
assert content_describer != null;
File = (FileInputStream) getContentResolver().openInputStream(content_describer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
try {
try {
try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd1.qcow2")) {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while (true) {
assert File != null;
if (!((len = File.read(buf)) > 0)) break;
out.write(buf, 0, len);
}
}
} finally {
Runnable runnable = () -> loading.setVisibility(View.GONE);
runOnUiThread(runnable);
assert File != null;
File.close();
}
} catch (IOException e) {
Runnable runnable = () -> {
loading.setVisibility(View.GONE);
UIAlert(this, e.toString(), "error");
};
runOnUiThread(runnable);
}
}).start();
} else if (requestCode == 1006 && resultCode == RESULT_OK) {
Uri content_describer = ReturnedIntent.getData();
ProgressBar loading = findViewById(R.id.loading);
loading.setVisibility(View.VISIBLE);
new Thread(() -> {
FileInputStream File;
try {
assert content_describer != null;
File = (FileInputStream) getContentResolver().openInputStream(content_describer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
try {
try {
try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + "/hdd2.qcow2")) {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while (true) {
assert File != null;
if (!((len = File.read(buf)) > 0)) break;
out.write(buf, 0, len);
}
}
} finally {
Runnable runnable = () -> loading.setVisibility(View.GONE);
runOnUiThread(runnable);
assert File != null;
File.close();
}
} catch (IOException e) {
Runnable runnable = () -> {
loading.setVisibility(View.GONE);
UIAlert(this, e.toString(), "error");
};
runOnUiThread(runnable);
}
}).start();
} else if (requestCode == 122 && resultCode == RESULT_OK) {
Uri content_describer = ReturnedIntent.getData();
File selectedFilePath = new File(getPath(content_describer));
ProgressBar loading = findViewById(R.id.loading);
loading.setVisibility(View.VISIBLE);
new Thread(() -> {
FileInputStream File;
try {
assert content_describer != null;
File = (FileInputStream) getContentResolver().openInputStream(content_describer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
try {
try {
File romDir = new File(AppConfig.maindirpath + curRomName + "/");
if (!romDir.exists()) {
if(!romDir.mkdirs()) return;
}
try (OutputStream out = new FileOutputStream(AppConfig.maindirpath + curRomName + "/" + "drv1-" + selectedFilePath.getName())) {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while (true) {
assert File != null;
if (!((len = File.read(buf)) > 0)) break;
out.write(buf, 0, len);
}
}
} finally {
Runnable runnable = () -> loading.setVisibility(View.GONE);
runOnUiThread(runnable);
assert File != null;
File.close();
}
} catch (IOException e) {
Runnable runnable = () -> {
loading.setVisibility(View.GONE);
UIAlert(this, e.toString(), "error");
};
runOnUiThread(runnable);
}
}).start();
if (isOpenRomStore) {
isOpenRomStore = false;
bindingContent.bottomNavigation.setSelectedItemId(R.id.item_romstore);
}
}
public String getPath(Uri uri) {
return FileUtils.getPath(this, uri);
}
private final ActivityResultLauncher<String> isoPicker =
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri == null) return;
if (VMManager.isAISOFile(FileUtils.getFileNameFromUri(this, uri))) {
importFile(uri, AppConfig.importedDriveFolder + "/drive.iso");
} else {
DialogUtils.twoDialog(this,
getString(R.string.problem_has_been_detected),
getString(R.string.file_format_is_not_supported),
getResources().getString(R.string.continuetext),
getResources().getString(R.string.cancel),
true,
R.drawable.album_24px,
true,
() -> importFile(uri, AppConfig.importedDriveFolder + "/drive.iso"),
null,
null);
}
});
private final ActivityResultLauncher<String> hdd1Picker =
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri == null) return;
if (VMManager.isADiskFile(FileUtils.getFileNameFromUri(this, uri))) {
importFile(uri, AppConfig.importedDriveFolder + "/hdd1.qcow2");
} else {
DialogUtils.twoDialog(this,
getString(R.string.problem_has_been_detected),
getString(R.string.file_format_is_not_supported),
getResources().getString(R.string.continuetext),
getResources().getString(R.string.cancel),
true,
R.drawable.hard_drive_24px,
true,
() -> importFile(uri, AppConfig.importedDriveFolder + "/hdd1.qcow2"),
null,
null);
}
});
private final ActivityResultLauncher<String> hdd2Picker =
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri == null) return;
if (VMManager.isADiskFile(FileUtils.getFileNameFromUri(this, uri))) {
importFile(uri, AppConfig.importedDriveFolder + "/hdd2.qcow2");
} else {
DialogUtils.twoDialog(this,
getString(R.string.problem_has_been_detected),
getString(R.string.file_format_is_not_supported),
getResources().getString(R.string.continuetext),
getResources().getString(R.string.cancel),
true,
R.drawable.hard_drive_24px,
true,
() -> importFile(uri, AppConfig.importedDriveFolder + "/hdd2.qcow2"),
null,
null);
}
});
private void setupDrawer() {
binding.drawerLayout.setScrimColor(Color.parseColor("#40000000")); //25%
@ -506,157 +396,82 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
w.setData(Uri.parse(tw));
startActivity(w);
} else if (id == R.id.navigation_item_import_iso) {
if (new File(AppConfig.maindirpath + "/drive.iso").exists()) {
AlertDialog ad;
ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create();
ad.setTitle("REPLACE ISO");
ad.setMessage("there is iso imported you want to replace it?");
ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1004);
});
ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> {
File isoFile = new File(AppConfig.maindirpath + "/drive.iso");
try {
if(!isoFile.delete()) Log.e(TAG, "Delete drive.iso failed!");
} catch (Exception e) {
Log.e(TAG, "Delete drive.iso: ", e);
}
});
ad.show();
if (new File(AppConfig.importedDriveFolder + "/drive.iso").exists()) {
DialogUtils.threeDialog(
this,
"Replace iso",
"There is iso imported you want to replace it?",
getString(R.string.replace),
getString(R.string.cancel),
getString(R.string.remove),
true,
R.drawable.album_24px,
true,
() -> isoPicker.launch("*/*"),
null,
() -> {
try {
File isoFile = new File(AppConfig.importedDriveFolder + "/drive.iso");
DialogUtils.fileDeletionResult(this, isoFile.delete());
} catch (Exception e) {
DialogUtils.fileDeletionResult(this, false);
}
},
null);
} else {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1004);
isoPicker.launch("*/*");
}
} else if (id == R.id.navigation_item_hdd1) {
if (new File(AppConfig.maindirpath + "/hdd1.qcow2").exists()) {
AlertDialog ad;
ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create();
ad.setTitle("REPLACE HDD1");
ad.setMessage("there is hdd1 imported you want to replace it?");
ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1006);
});
ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> {
File isoFile = new File(AppConfig.maindirpath + "/hdd1.qcow2");
try {
if(!isoFile.delete()) Log.e(TAG, "Delete hdd1.qcow2 failed!");
} catch (Exception e) {
Log.e(TAG, "Delete hdd1.qcow2: ", e);
}
});
ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> {
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd1.qcow2");
if (fileWithinMyDir.exists()) {
intentShareFile.setType("*/*");
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd1.qcow2"));
intentShareFile.putExtra(Intent.EXTRA_SUBJECT,
"Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
});
ad.show();
if (new File(AppConfig.importedDriveFolder + "/hdd1.qcow2").exists()) {
DialogUtils.threeDialog(
this,
"Replace HDD1",
"There is HDD1 imported you want to replace it?",
getString(R.string.replace),
getString(R.string.cancel),
getString(R.string.remove),
true,
R.drawable.hard_drive_24px,
true,
() -> hdd1Picker.launch("*/*"),
null,
() -> {
try {
File hdd1File = new File(AppConfig.importedDriveFolder + "/hdd1.qcow2");
DialogUtils.fileDeletionResult(this, hdd1File.delete());
} catch (Exception e) {
DialogUtils.fileDeletionResult(this, false);
}
},
null);
} else {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1005);
hdd1Picker.launch("*/*");
}
} else if (id == R.id.navigation_item_hdd2) {
if (new File(AppConfig.maindirpath + "/hdd2.qcow2").exists()) {
AlertDialog ad;
ad = new AlertDialog.Builder(this, R.style.MainDialogTheme).create();
ad.setTitle("REPLACE HDD2");
ad.setMessage("there is hdd2 imported you want to replace it?");
ad.setButton(Dialog.BUTTON_POSITIVE, "REPLACE", (dialog, which) -> {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1006);
});
ad.setButton(Dialog.BUTTON_NEGATIVE, "REMOVE", (dialog, which) -> {
File isoFile = new File(AppConfig.maindirpath + "/hdd2.qcow2");
try {
if(!isoFile.delete()) Log.e(TAG, "Delete hdd2.qcow2 failed!");
} catch (Exception e) {
Log.e(TAG, "Delete hdd2.qcow2: ", e);
}
});
ad.setButton(Dialog.BUTTON_NEUTRAL, "SHARE", (dialog, which) -> {
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
File fileWithinMyDir = new File(AppConfig.maindirpath + "/hdd2.qcow2");
if (fileWithinMyDir.exists()) {
intentShareFile.setType("*/*");
intentShareFile.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + AppConfig.maindirpath + "/hdd2.qcow2"));
intentShareFile.putExtra(Intent.EXTRA_SUBJECT,
"Sharing File...");
intentShareFile.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
startActivity(Intent.createChooser(intentShareFile, "Share File"));
}
});
ad.show();
if (new File(AppConfig.importedDriveFolder + "/hdd2.qcow2").exists()) {
DialogUtils.threeDialog(
this,
"Replace HDD2",
"There is HDD2 imported you want to replace it?",
getString(R.string.replace),
getString(R.string.cancel),
getString(R.string.remove),
true,
R.drawable.hard_drive_24px,
true,
() -> hdd2Picker.launch("*/*"),
null,
() -> {
try {
File hdd1File = new File(AppConfig.importedDriveFolder + "/hdd2.qcow2");
DialogUtils.fileDeletionResult(this, hdd1File.delete());
} catch (Exception e) {
DialogUtils.fileDeletionResult(this, false);
}
},
null);
} else {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1006);
hdd2Picker.launch("*/*");
}
} else if (id == R.id.navigation_item_desktop) {
DisplaySystem.launchX11(this, true);
@ -714,7 +529,8 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
} else if (id == R.id.navigation_item_store) {
startActivity(new Intent(this, StoreActivity.class));
} else if (id == R.id.navigation_data_explorer) {
startActivity(new Intent(this, DataExplorerActivity.class));
// startActivity(new Intent(this, DataExplorerActivity.class));
FileUtils.openFolder(this, AppConfig.maindirpath);
} else if (id == R.id.navigation_item_donate) {
String tw = "https://www.patreon.com/VectrasTeam";
Intent w = new Intent(ACTION_VIEW);
@ -803,7 +619,7 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
}
};
requestNetwork.startRequestNetwork(RequestNetworkController.GET,AppConfig.updateJson,"maincheckupdate",requestNetworkListener);
requestNetwork.startRequestNetwork(RequestNetworkController.GET, AppConfig.updateJson, "maincheckupdate", requestNetworkListener);
}
@SuppressLint("NotifyDataSetChanged")
@ -845,4 +661,42 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
adapterRomStoreSearch.notifyDataSetChanged();
}
private void importFile(Uri uri, String copyTo) {
if (uri == null) return;
View progressView = LayoutInflater.from(this).inflate(R.layout.dialog_progress_style, null);
TextView progress_text = progressView.findViewById(R.id.progress_text);
progress_text.setText(getString(R.string.importing_file));
AlertDialog progressDialog = new MaterialAlertDialogBuilder(this, R.style.CenteredDialogTheme)
.setView(progressView)
.setCancelable(false)
.create();
progressDialog.show();
AtomicBoolean isCompleted = new AtomicBoolean(false);
executor.execute(() -> {
try {
FileUtils.copyFileFromUri(this, uri, copyTo);
isCompleted.set(true);
} catch (Exception e) {
isCompleted.set(false);
} finally {
runOnUiThread(() -> {
progressDialog.dismiss();
DialogUtils.oneDialog(
this,
isCompleted.get() ? getString(R.string.imported) : getString(R.string.oops),
isCompleted.get() ? getString(R.string.file_imported_successfully) : getString(R.string.file_import_failed),
getString(R.string.ok),
true,
isCompleted.get() ? R.drawable.check_24px : R.drawable.error_96px,
true,
null,
null
);
});
}
});
}
}

View file

@ -27,6 +27,7 @@ import com.vectras.vm.VMManager;
import com.vectras.vm.logger.VectrasStatus;
import com.vectras.vm.settings.ExternalVNCSettingsActivity;
import com.vectras.vm.utils.DialogUtils;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vm.utils.NetworkUtils;
import com.vectras.vm.utils.ServiceUtils;
@ -59,6 +60,25 @@ public class HomeStartVM {
return;
}
if (MainSettingsManager.getSharedFolder(activity)
&& !MainSettingsManager.getArch(activity).equals("I386")
&& FileUtils.getFolderSize(FileUtils.getExternalFilesDirectory(activity).getPath() + "/SharedFolder") / Math.pow(10, 2) > 516) {
DialogUtils.twoDialog(
activity,
activity.getString(R.string.problem_has_been_detected),
activity.getString(R.string.shared_folder_is_too_large_content),
activity.getString(R.string.open_shared_folder),
activity.getString(R.string.close),
true,
R.drawable.warning_48px,
true,
() -> FileUtils.openFolder(activity, FileUtils.getExternalFilesDirectory(activity).getPath() + "/SharedFolder"),
null,
null
);
return;
}
VMManager.lastQemuCommand = env;
if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) {

View file

@ -2,6 +2,7 @@ package com.vectras.vm.settings;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
@ -25,10 +26,16 @@ public class VNCSettingsActivity extends AppCompatActivity {
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
binding.toolbar.setNavigationOnClickListener(view -> onBackPressed());
binding.toolbar.setNavigationOnClickListener(view -> finish());
initialize();
}
@Override
public void onResume() {
super.onResume();
binding.cvNotusingvnc.setVisibility(MainSettingsManager.getVmUi(this).equals("VNC") ? View.GONE : View.VISIBLE);
}
private void initialize() {
binding.swForcerefesh.setOnCheckedChangeListener((buttonView, isChecked) -> MainSettingsManager.setForceRefeshVNCDisplay(this, isChecked));
binding.lnForcerefesh.setOnClickListener(v -> binding.swForcerefesh.toggle());
@ -38,5 +45,12 @@ public class VNCSettingsActivity extends AppCompatActivity {
binding.swForcerefesh.setChecked(MainSettingsManager.getForceRefeshVNCDisplay(this));
binding.swExternal.setChecked(MainSettingsManager.getVncExternal(this));
binding.lnNotusingvnc.setOnClickListener(v -> {
Intent intent = new Intent();
intent.putExtra("goto", "qemu");
intent.setClass(this, MainSettingsManager.class);
startActivity(intent);
});
}
}

View file

@ -60,6 +60,7 @@ public class DialogUtils {
});
dialog.show();
}
public static void twoDialog(Activity _context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(_context).inflate(R.layout.dialog_layout, null);
@ -111,7 +112,7 @@ public class DialogUtils {
dialog.show();
}
public static void threeDialog(Activity _context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, String _textNeutralButton ,boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onNeutral, Runnable _onDismiss) {
public static void threeDialog(Activity _context, String _title, String _message, String _textPositiveButton, String _textNegativeButton, String _textNeutralButton, boolean _isicon, int _iconid, boolean _cancel, Runnable _onPositive, Runnable _onNegative, Runnable _onNeutral, Runnable _onDismiss) {
View buttonsView = LayoutInflater.from(_context).inflate(R.layout.dialog_layout, null);
AlertDialog dialog = new AlertDialog.Builder(_context).create();
@ -191,4 +192,32 @@ public class DialogUtils {
}, null);
}
}
public static void fileDeletionResult(Activity activity, boolean isCompleted) {
if (isCompleted) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.done),
activity.getString(R.string.file_deleted),
activity.getString(R.string.ok),
true,
R.drawable.check_24px,
true,
null,
null
);
} else {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.delete_file_failed_content),
activity.getString(R.string.ok),
true,
R.drawable.error_96px,
true,
null,
null
);
}
}
}

View file

@ -3,6 +3,7 @@ package com.vectras.vm.utils;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
@ -31,6 +32,7 @@ import android.os.Looper;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import com.vectras.vm.R;
@ -49,6 +51,8 @@ import java.util.Objects;
* @author dev
*/
public class FileUtils {
public static final String TAG = "FileUtils";
@NonNull
public static File getExternalFilesDirectory(Context context) {
return new File(Environment.getExternalStorageDirectory(), "Documents/VectrasVM");
@ -793,7 +797,7 @@ public class FileUtils {
}
}
public static int getFolderSize(String _path) {
public static long getFolderSize(String _path) {
try {
File file;
file = new File(_path);
@ -822,7 +826,7 @@ public class FileUtils {
}
}
}
return (int) result;
return result;
} catch (Exception _e) {
return 0;
}
@ -832,19 +836,14 @@ public class FileUtils {
String filePath = null;
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {MediaStore.Files.FileColumns.DATA};
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA);
filePath = cursor.getString(index);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
int index = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA);
filePath = cursor.getString(index);
}
} catch (Exception e) {
Log.e(TAG, "getFilePathFromUri: ", e);
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
filePath = uri.getPath();
}
@ -868,4 +867,53 @@ public class FileUtils {
}
return true;
}
public static void openFolder(Activity activity, String folderPath) {
File folder = new File(folderPath);
if (!folder.exists() || !folder.isDirectory()) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.directory_does_not_exist),
activity.getString(R.string.ok),
true,
R.drawable.error_96px,
true,
null,
null
);
Log.e(TAG, "openFolder: Folder not found!");
return;
}
Uri uri = FileProvider.getUriForFile(
activity,
activity.getPackageName() + ".provider",
folder
);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "resource/folder");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
activity.startActivity(intent);
} catch (Exception e) {
DialogUtils.oneDialog(
activity,
activity.getString(R.string.oops),
activity.getString(R.string.there_is_no_app_to_perform_this_action),
activity.getString(R.string.ok),
true,
R.drawable.error_96px,
true,
null,
null
);
Log.e(TAG, "openFolder: " + e.getMessage());
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View 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="M478,720Q499,720 513.5,705.5Q528,691 528,670Q528,649 513.5,634.5Q499,620 478,620Q457,620 442.5,634.5Q428,649 428,670Q428,691 442.5,705.5Q457,720 478,720ZM442,566L516,566Q516,533 523.5,514Q531,495 566,462Q592,436 607,412.5Q622,389 622,356Q622,300 581,270Q540,240 484,240Q427,240 391.5,270Q356,300 342,342L408,368Q413,350 430.5,329Q448,308 484,308Q516,308 532,325.5Q548,343 548,364Q548,384 536,401.5Q524,419 506,434Q462,473 452,493Q442,513 442,566ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
</vector>

View 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="M787,815L815,787L740,712L740,600L700,600L700,728L787,815ZM200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,468Q821,459 801,452.5Q781,446 760,443L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L442,760Q445,782 451.5,802Q458,822 467,840L200,840ZM200,720Q200,731 200,740.5Q200,750 200,760L200,760Q200,760 200,760Q200,760 200,760L200,200Q200,200 200,200Q200,200 200,200L200,200Q200,200 200,200Q200,200 200,200L200,443Q200,441 200,440.5Q200,440 200,440Q200,440 200,522Q200,604 200,720ZM280,680L443,680Q446,659 452.5,639Q459,619 467,600L280,600L280,680ZM280,520L524,520Q556,490 595.5,470Q635,450 680,443L680,440L280,440L280,520ZM280,360L680,360L680,280L280,280L280,360ZM720,920Q637,920 578.5,861.5Q520,803 520,720Q520,637 578.5,578.5Q637,520 720,520Q803,520 861.5,578.5Q920,637 920,720Q920,803 861.5,861.5Q803,920 720,920Z"/>
</vector>

View file

@ -47,6 +47,35 @@
android:orientation="vertical"
android:animateLayoutChanges="true">
<com.google.android.material.card.MaterialCardView
android:id="@+id/cv_notusingvnc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardBackgroundColor="?attr/colorSurfaceContainer"
style="@style/Widget.Material3.CardView.Filled"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:id="@+id/ln_notusingvnc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/warning_48px"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:text="@string/you_are_using_x11_instead_of_vnc_content"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ln_forcerefesh"
android:layout_width="match_parent"

View file

@ -12,23 +12,18 @@
android:title="@string/roms_store" />
<item
android:id="@+id/navigation_item_import_iso"
android:icon="@drawable/round_album_24"
android:icon="@drawable/album_24px"
android:title="@string/import_iso"
android:visible="false"/>
<item
android:id="@+id/navigation_item_hdd1"
android:icon="@drawable/round_storage_24"
android:icon="@drawable/hard_drive_24px"
android:title="@string/hdd1"/>
<item
android:id="@+id/navigation_item_hdd2"
android:icon="@drawable/round_storage_24"
android:icon="@drawable/hard_drive_24px"
android:title="@string/hdd2"
android:visible="false"/>
<item
android:id="@+id/navigation_data_explorer"
android:icon="@drawable/round_folder_24"
android:visible="false"
android:title="@string/data_explorer"/>
<item
android:id="@+id/navigation_item_desktop"
android:icon="@drawable/desktop_24px"
@ -39,31 +34,35 @@
android:title="@string/terminal"/>
<item
android:id="@+id/navigation_item_view_logs"
android:icon="@drawable/round_adb_24"
android:icon="@drawable/overview_24px"
android:title="@string/view_logs" />
<item
android:id="@+id/navigation_item_settings"
android:icon="@drawable/round_settings_24"
android:icon="@drawable/settings_24px"
android:title="@string/settings"/>
<item
android:id="@+id/mini_tools"
android:icon="@drawable/home_repair_service_24px"
android:title="@string/mini_tools"/>
<item
android:id="@+id/navigation_data_explorer"
android:icon="@drawable/folder_24px"
android:title="@string/open_main_folder"/>
<item
android:id="@+id/navigation_item_website"
android:icon="@drawable/round_public_24"
android:title="@string/vectras_website" />
<item
android:id="@+id/navigation_item_donate"
android:icon="@drawable/ic_patreon"
android:icon="@drawable/patreon_outline_225"
android:title="@string/patreon"/>
<item
android:id="@+id/navigation_item_help"
android:icon="@drawable/round_help_24"
android:icon="@drawable/help_24px"
android:title="@string/help"/>
<item
android:id="@+id/navigation_item_info"
android:icon="@drawable/round_info_24"
android:icon="@drawable/info_24px"
android:title="@string/about"/>
</menu>

View file

@ -3,7 +3,7 @@
<string name="app_name">Vectras VM</string>
<!--======================VECTRAS STRINGS====================-->
<string name="app_version" translatable="false">v2.9.5.11-3dfx</string>
<string name="app_version" translatable="false">v2.9.5.12-3dfx</string>
<string name="qemu_version" translatable="false">Stable</string>
<string name="str_home">Home</string>
<string name="str_logger">Logger</string>
@ -54,7 +54,7 @@
<string name="login_failed">"Login failed"</string>
<string name="profile">Profile</string>
<string name="apps_amp_games"><![CDATA[Apps & Games]]></string>
<string name="vectras_website">Vectras Website</string>
<string name="vectras_website">Vectras website</string>
<string name="about">About</string>
<string name="emulation_information">Emulation Information</string>
<string name="full_name">Full Name</string>
@ -81,7 +81,7 @@
<string name="calibrate_mouse">Calibrate Mouse</string>
<string name="hide_controller">HIDE CONTROLLER</string>
<string name="remove">Remove</string>
<string name="view_logs">View Logs</string>
<string name="view_logs">View logs</string>
<string name="title_activity_set_arch">SetArchActivity</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
@ -556,6 +556,19 @@
<string name="force_refresh">Force refresh</string>
<string name="force_refresh_vnc_description">The VNC screen will restart every time there is a change, which helps troubleshoot problems.</string>
<string name="settings_for_vnc">Settings for VNC.</string>
<string name="imported">Imported</string>
<string name="file_imported_successfully">File imported successfully.</string>
<string name="file_import_failed">File import failed.</string>
<string name="importing_file">Importing file…</string>
<string name="replace">Replace</string>
<string name="delete_file_failed_content">An error occurred while deleting the file, please try again later.</string>
<string name="file_deleted">File deleted.</string>
<string name="open_main_folder">Open main folder</string>
<string name="you_are_using_x11_instead_of_vnc_content">You are using X11 instead of VNC. To use VNC, go to Settings, go to QEMU, scroll down to the bottom and in the UI select VNC.</string>
<string name="there_is_no_app_to_perform_this_action">There is no app to perform this action.</string>
<string name="directory_does_not_exist">Directory does not exist.</string>
<string name="shared_folder_is_too_large_content">The shared folder is too large. Please delete some of the following files so that the total size of all files in the shared folder does not exceed 516 MB.</string>
<string name="open_shared_folder">Open shared folder</string>
<!--======================TERMUX STRINGS====================-->

View file

@ -0,0 +1,5 @@
<paths>
<external-path
name="external_files"
path="." />
</paths>

View file

@ -1,15 +1,15 @@
{
"versionCode":"21",
"versionName":"v2.9.5-3dfx,v2.9.5-3dfx-almondcake,v2.9.5-3dfx-bread,v2.9.5-3dfx-churro,v2.9.5-3dfx-doughnut,v2.9.5-3dfx-empanada,v2.9.5-3dfx-flan,v2.9.5-3dfx-gugelhupf,v2.9.5-3dfx-hamentaschen,v2.9.5-3dfx-italianice,v2.9.5-3dfx-ladyfingers,v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-ube-halaya,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx,v2.9.5.8-3dfx,v2.9.5.9-3dfx,v2.9.5.10-3dfx,v2.9.5.11-3dfx",
"versionName":"v2.9.5-3dfx,v2.9.5-3dfx-almondcake,v2.9.5-3dfx-bread,v2.9.5-3dfx-churro,v2.9.5-3dfx-doughnut,v2.9.5-3dfx-empanada,v2.9.5-3dfx-flan,v2.9.5-3dfx-gugelhupf,v2.9.5-3dfx-hamentaschen,v2.9.5-3dfx-italianice,v2.9.5-3dfx-ladyfingers,v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-ube-halaya,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx,v2.9.5.8-3dfx,v2.9.5.9-3dfx,v2.9.5.10-3dfx,v2.9.5.11-3dfx,v2.9.5.12-3dfx",
"size": "46 MB",
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases/v2.9.5",
"Message": "<h2>v2.9.5-3dfx</h2><ul><li>Bring back 3dfx support.</li><li>Enhance app execution.</li><li>Added some linux programs in x11 display.</li><li>Added alpine linux (x11).</li><li>Russian language by <a href=\"https://github.com/OFGING\" target=\"_blank\">@OFGING</a></li></ul><br><br>New updates are live!",
"cancellable": true,
"versionCodeBeta":"21",
"versionNameBeta":"v2.9.5.11-3dfx",
"versionNameBetas":"v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx,v2.9.5.8-3dfx,v2.9.5.9-3dfx,v2.9.5.10-3dfx,v2.9.5.11-3dfx",
"versionNameBeta":"v2.9.5.12-3dfx",
"versionNameBetas":"v2.9.5-3dfx-madeleine,v2.9.5-3dfx-neapolitanicecream,v2.9.5-3dfx-orangecake,v2.9.5-3dfx-profiterole,v2.9.5-3dfx-quincejelly,v2.9.5-3dfx-rugelach,v2.9.5-3dfx-scone,v2.9.5-3dfx-tart,v2.9.5-3dfx-victoria-sponge,v2.9.5-3dfx-waffle,v2.9.5-3dfx-xangos,v2.9.5-3dfx-yorkshire-pudding,v2.9.5-3dfx-zeppole,v2.9.5.1-3dfx,v2.9.5.2-3dfx,v2.9.5.3-3dfx,v2.9.5.4-3dfx,v2.9.5.5-3dfx,v2.9.5.6-3dfx,v2.9.5.7-3dfx,v2.9.5.8-3dfx,v2.9.5.9-3dfx,v2.9.5.10-3dfx,v2.9.5.11-3dfx,v2.9.5.12-3dfx",
"sizeBeta": "41 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>v2.9.5.11-3dfx</h2>Bugs fixed.",
"MessageBeta": "<h2>v2.9.5.12-3dfx</h2>Bugs fixed.",
"cancellableBeta": true
}