Merge pull request #412 from AnBui2004/master

v2.9.5.13-3dfx
This commit is contained in:
An Bui 2025-10-06 17:22:33 +07:00 committed by GitHub
commit 560e64a416
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 508 additions and 666 deletions

View file

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-09-17T10:28:29.318864400Z">
<DropdownSelection timestamp="2025-10-06T04:13:53.525283500Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="Default" identifier="serial=192.168.1.99:40965;connection=580054e5" />
<DeviceId pluginId="LocalEmulator" identifier="path=E:\Android\AVD\avd\Pixel_9_Pro_XL.avd" />
</handle>
</Target>
</DropdownSelection>

View file

@ -11,7 +11,7 @@ android {
minSdk minApi
targetSdk targetApi
versionCode 21
versionName "v2.9.5.12-3dfx"
versionName "v2.9.5.13-3dfx"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}

View file

@ -49,6 +49,7 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.vectras.vm.AppConfig;
import com.vectras.vm.R;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.TerminalColors;
@ -165,8 +166,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
void checkForFontAndColors() {
try {
@SuppressLint("SdCardPath") File fontFile = new File("/data/data/com.vectras.vm/files/home/.termux/font.ttf");
@SuppressLint("SdCardPath") File colorsFile = new File("/data/data/com.vectras.vm/files/home/.termux/colors.properties");
@SuppressLint("SdCardPath") File fontFile = new File(AppConfig.internalDataDirPath + "home/.termux/font.ttf");
@SuppressLint("SdCardPath") File colorsFile = new File(AppConfig.internalDataDirPath + "home/.termux/colors.properties");
final Properties props = new Properties();
if (colorsFile.isFile()) {

View file

@ -69,7 +69,7 @@ final class TermuxInstaller {
@Override
public void run() {
try {
final String STAGING_PREFIX_PATH = TermuxService.FILES_PATH + "/usr-staging";
final String STAGING_PREFIX_PATH = TermuxService.FILES_PATH + "usr-staging";
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
if (STAGING_PREFIX_FILE.exists()) {

View file

@ -21,6 +21,7 @@ import android.provider.Settings;
import android.util.Log;
import android.widget.ArrayAdapter;
import com.vectras.vm.AppConfig;
import com.vectras.vm.R;
import com.termux.terminal.EmulatorDebug;
import com.termux.terminal.TerminalSession;
@ -48,10 +49,10 @@ public final class TermuxService extends Service implements SessionChangedCallba
/** Note that this is a symlink on the Android M preview. */
@SuppressLint("SdCardPath")
public static final String FILES_PATH = "/data/data/com.vectras.vm/files";
public static final String PREFIX_PATH = FILES_PATH + "/usr";
public static final String HOME_PATH = FILES_PATH + "/home";
public static final String OPT_PATH = FILES_PATH + "/fex-rootfs/opt";
public static final String FILES_PATH = AppConfig.internalDataDirPath;
public static final String PREFIX_PATH = FILES_PATH + "usr";
public static final String HOME_PATH = FILES_PATH + "home";
public static final String OPT_PATH = FILES_PATH + "fex-rootfs/opt";
private static final int NOTIFICATION_ID = 1337;

View file

@ -25,7 +25,7 @@ import java.util.regex.Pattern;
public class TermuxFileReceiverActivity extends Activity {
static final String TERMUX_RECEIVEDIR = TermuxService.FILES_PATH + "/home/downloads";
static final String TERMUX_RECEIVEDIR = TermuxService.FILES_PATH + "home/downloads";
static final String EDITOR_PROGRAM = TermuxService.HOME_PATH + "/bin/termux-file-editor";
static final String URL_OPENER_PROGRAM = TermuxService.HOME_PATH + "/bin/termux-url-opener";

View file

@ -971,7 +971,19 @@ public class MainSettingsManager extends AppCompatActivity
public static Boolean getForceRefeshVNCDisplay(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("forceRefeshVNCDisplay", false);
return prefs.getBoolean("forceRefeshVNCDisplay", true);
}
public static void setQuickStart(Context context, Boolean _boolean) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean("quickStart", _boolean);
edit.apply();
}
public static Boolean getQuickStart(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("quickStart", true);
}
}

View file

@ -1,19 +1,13 @@
package com.vectras.vm;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.LinearLayoutManager;
//import com.google.android.gms.ads.MobileAds;
//import com.google.android.gms.ads.initialization.InitializationStatus;
//import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
//import com.google.android.gms.ads.interstitial.InterstitialAd;
import com.vectras.vm.adapters.GithubUserAdapter;
import com.vectras.vm.utils.UIUtils;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -30,15 +24,10 @@ import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import com.vectras.vm.R;
import com.vectras.vterm.Terminal;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Objects;
public class AboutActivity extends AppCompatActivity implements View.OnClickListener{
@ -57,7 +46,7 @@ public class AboutActivity extends AppCompatActivity implements View.OnClickList
// UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main));
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setTitle(getResources().getString(R.string.about));
//btn

View file

@ -64,6 +64,7 @@ public class AppConfig {
return activity.getExternalFilesDir("data") + "/Vectras";
//return FileUtils.getExternalFilesDirectory(activity).getPath();
}
public static String internalDataDirPath = "/data/data/com.vectras.vm/files/";
public static String basefiledir = "";
public static String maindirpath = "";
public static String recyclebin = "";

View file

@ -69,7 +69,7 @@ public class AudioStreamService extends Service {
new Thread(() -> {
try {
LocalSocket socket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(TermuxService.FILES_PATH + "/run/pulse/native",
LocalSocketAddress address = new LocalSocketAddress(TermuxService.FILES_PATH + "run/pulse/native",
LocalSocketAddress.Namespace.FILESYSTEM);
socket.connect(address);

View file

@ -25,9 +25,8 @@ import java.util.Objects;
public class CqcmActivity extends AppCompatActivity {
private Intent gotoActivity = new Intent();
private Intent openURL = new Intent();
private Button buttonallow;
private final Intent gotoActivity = new Intent();
private final Intent openURL = new Intent();
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -36,7 +35,8 @@ public class CqcmActivity extends AppCompatActivity {
UIUtils.edgeToEdge(this);
setContentView(R.layout.activity_cqcm);
UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main));
buttonallow = findViewById(R.id.buttonallow);
Button buttonallow = findViewById(R.id.buttonallow);
buttonallow.setOnClickListener(v -> {
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
@ -64,7 +64,7 @@ public class CqcmActivity extends AppCompatActivity {
}
private void startAdd() {
HashMap<String, Object> mapForCreateNewVM = new HashMap<>();
HashMap<String, Object> mapForCreateNewVM;
String _map;
String imgName = "";
String imgIcon = "";
@ -81,7 +81,7 @@ public class CqcmActivity extends AppCompatActivity {
if (JSONUtils.isValidFromFile(AppConfig.romsdatajson)) {
if (getIntent().hasExtra("content")) {
if (Objects.requireNonNull(getIntent().getStringExtra("content")).endsWith("}]")) {
_map = Objects.requireNonNull(getIntent().getStringExtra("content")).substring((int) 0, (int)(Objects.requireNonNull(getIntent().getStringExtra("content")).length() - 1));
_map = Objects.requireNonNull(getIntent().getStringExtra("content")).substring(0, Objects.requireNonNull(getIntent().getStringExtra("content")).length() - 1);
} else {
_map = Objects.requireNonNull(getIntent().getStringExtra("content"));
}

View file

@ -3,7 +3,6 @@ package com.vectras.vm;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;

View file

@ -1,24 +1,16 @@
package com.vectras.vm;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.google.gson.Gson;
@ -41,7 +33,7 @@ import java.util.TimerTask;
public class ExportRomActivity extends AppCompatActivity {
private Timer _timer = new Timer();
private final Timer _timer = new Timer();
private TimerTask timerTask;
private LinearLayout linearone;
private LinearLayout linearload;
@ -61,9 +53,6 @@ public class ExportRomActivity extends AppCompatActivity {
public String cdromfile = "";
private int folderSize = 0;
private int zipFileSize = 0;
private double zipprogress = 0;
private double zipprogresslast = 0;
private double folderSizeMB = 0;
private LinearProgressIndicator progressBar;
private TextView textviewsettingup;
private int compressionProgress = 0;
@ -89,34 +78,21 @@ public class ExportRomActivity extends AppCompatActivity {
Button buttondone;
buttondone = findViewById(R.id.materialbutton1);
buttondone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
editauthor.setEnabled(false);
editdesc.setEnabled(false);
editauthor.setEnabled(true);
editdesc.setEnabled(true);
startCreateCVBI();
}
buttondone.setOnClickListener(v -> {
editauthor.setEnabled(false);
editdesc.setEnabled(false);
editauthor.setEnabled(true);
editdesc.setEnabled(true);
startCreateCVBI();
});
Button buttonexit;
buttonexit = findViewById(R.id.buttonexit);
buttonexit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
buttonexit.setOnClickListener(v -> finish());
Button buttonexit2;
buttonexit2 = findViewById(R.id.buttonexit2);
buttonexit2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
buttonexit2.setOnClickListener(v -> finish());
data= getSharedPreferences("data", Activity.MODE_PRIVATE);
editauthor.setText(data.getString("author", ""));
@ -126,8 +102,8 @@ public class ExportRomActivity extends AppCompatActivity {
@Override
public void onPause() {
super.onPause();
data.edit().putString("author", editauthor.getText().toString()).commit();
data.edit().putString("desc", editdesc.getText().toString()).commit();
data.edit().putString("author", editauthor.getText().toString()).apply();
data.edit().putString("desc", editdesc.getText().toString()).apply();
}
private void UIControler(int _status, String _content) {
@ -138,7 +114,7 @@ public class ExportRomActivity extends AppCompatActivity {
linearone.setVisibility(View.GONE);
linearload.setVisibility(View.GONE);
lineardone.setVisibility(View.VISIBLE);
textviewfilename.setText(getResources().getString(R.string.saved_in) + " " +_content);
textviewfilename.setText(getString(R.string.saved_in) + " " + _content);
} else if (_status == 2) {
linearone.setVisibility(View.GONE);
linearload.setVisibility(View.GONE);
@ -153,7 +129,9 @@ public class ExportRomActivity extends AppCompatActivity {
File vDir = new File(AppConfig.maindirpath + "cvbi");
if (!vDir.exists()) {
vDir.mkdirs();
if(!vDir.mkdirs()) {
UIControler(2, getString(R.string.could_not_create_dir_to_save_cvbi_content));
}
}
listmapForGetData.clear();
@ -161,7 +139,7 @@ public class ExportRomActivity extends AppCompatActivity {
listmapForGetData = new Gson().fromJson(FileUtils.readAFile(AppConfig.romsdatajson), new TypeToken<ArrayList<HashMap<String, Object>>>(){}.getType());
getRomPath = AppConfig.vmFolder + Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("vmID")).toString() + "/";
getRomPath = AppConfig.vmFolder + Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("vmID")) + "/";
if (listmapForGetData.get(pendingPosition).containsKey("imgName")) {
mapForGetData.put("title", Objects.requireNonNull(listmapForGetData.get(pendingPosition).get("imgName")).toString());
@ -235,19 +213,16 @@ public class ExportRomActivity extends AppCompatActivity {
timerTask = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
zipFileSize = FileUtils.getFileSize(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi");
compressionProgress = ZipUtils.getCompressionProgress(folderSize, zipFileSize);
if (compressionProgress > 0) {
if (compressionProgress > 98) {
progressBar.setIndeterminate(true);
} else {
progressBar.setProgressCompat(compressionProgress, true);
}
textviewsettingup.setText(getResources().getString(R.string.about) + " " + String.valueOf(ZipUtils.getRemainingCompressionTime(folderSize, zipFileSize)) + " " + getResources().getString(R.string.seconds_left));
runOnUiThread(() -> {
zipFileSize = FileUtils.getFileSize(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi");
compressionProgress = ZipUtils.getCompressionProgress(folderSize, zipFileSize);
if (compressionProgress > 0) {
if (compressionProgress > 98) {
progressBar.setIndeterminate(true);
} else {
progressBar.setProgressCompat(compressionProgress, true);
}
textviewsettingup.setText(getResources().getString(R.string.about) + " " + ZipUtils.getRemainingCompressionTime(folderSize, zipFileSize) + " " + getResources().getString(R.string.seconds_left));
}
});
}
@ -265,73 +240,64 @@ public class ExportRomActivity extends AppCompatActivity {
new FileSource("/" + new File(cdromfile).getName(), new File(cdromfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if ((!iconfile.isEmpty()) && (!diskfile.isEmpty())) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(diskfile).getName(), new File(diskfile)),
new FileSource("/" + new File(iconfile).getName(), new File(iconfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if ((!iconfile.isEmpty()) && (!cdromfile.isEmpty())) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(iconfile).getName(), new File(iconfile)),
new FileSource("/" + new File(cdromfile).getName(), new File(cdromfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if ((!diskfile.isEmpty()) && (!cdromfile.isEmpty())) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(diskfile).getName(), new File(diskfile)),
new FileSource("/" + new File(cdromfile).getName(), new File(cdromfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if (!iconfile.isEmpty()) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(iconfile).getName(), new File(iconfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if (!diskfile.isEmpty()) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(diskfile).getName(), new File(diskfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else if (!cdromfile.isEmpty()) {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(cdromfile).getName(), new File(cdromfile)),
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
} else {
ZipEntrySource[] addedEntries = new ZipEntrySource[]{
new FileSource("/" + new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json").getName(), new File(getApplicationContext().getExternalFilesDir("data") + "/rom-data.json"))
};
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi"));
ZipUtil.pack(addedEntries, new File(FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi"));
}
runOnUiThread(new Runnable() {
@Override
public void run() {
UIControler(1, FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")).toString() + ".cvbi");
if (timerTask != null) {
timerTask.cancel();
}
runOnUiThread(() -> {
UIControler(1, FileUtils.getExternalFilesDirectory(getApplicationContext()).getPath() + "/cvbi/" + Objects.requireNonNull(mapForGetData.get("title")) + ".cvbi");
if (timerTask != null) {
timerTask.cancel();
}
});
} catch (Exception e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
UIControler(2, e.toString());
}
});
runOnUiThread(() -> UIControler(2, e.toString()));
}
}
};
t.start();
return;
}
}

View file

@ -6,7 +6,6 @@ import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.vectras.vm.R;
import com.vectras.vm.utils.UIUtils;
public class ImagePrvActivity extends AppCompatActivity {

View file

@ -804,14 +804,14 @@ public class MainActivity extends AppCompatActivity {
VMManager.lastQemuCommand = env;
if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) {
Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show();
if (MainSettingsManager.getVmUi(activity).equals("VNC"))
activity.startActivity(new Intent(activity, MainVNCActivity.class));
else if (MainSettingsManager.getVmUi(activity).equals("X11"))
activity.launchX11(false);
return;
}
// if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) {
// Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show();
// if (MainSettingsManager.getVmUi(activity).equals("VNC"))
// activity.startActivity(new Intent(activity, MainVNCActivity.class));
// else if (MainSettingsManager.getVmUi(activity).equals("X11"))
// activity.launchX11(false);
// return;
// }
if (AppConfig.getSetupFiles().contains("arm") && !AppConfig.getSetupFiles().contains("arm64")) {
if (env.contains("tcg,thread=multi")) {

View file

@ -61,18 +61,16 @@ public class MainService extends Service {
}
public static void stopService() {
Thread t = new Thread(new Runnable() {
public void run() {
if (service != null) {
service.stopForeground(true);
service.stopSelf();
//TODO: Not Work
//Terminal.killQemuProcess();
VMManager.killallqemuprocesses(activity);
}
Thread t = new Thread(() -> {
if (service != null) {
service.stopForeground(true);
service.stopSelf();
//TODO: Not Work
//Terminal.killQemuProcess();
VMManager.killallqemuprocesses(activity);
}
});
t.setName("HomeStartVM");
t.start();
@ -112,7 +110,9 @@ public class MainService extends Service {
public static void startCommand(String _env, Activity _activity) {
Terminal vterm = new Terminal(_activity);
vterm.executeShellCommand2("dwm", false, _activity);
if (Build.VERSION.SDK_INT < 34) {
vterm.executeShellCommand2("dwm", false, _activity);
}
vterm.executeShellCommand2(_env, true, _activity);
}
}

View file

@ -9,6 +9,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@ -44,7 +45,7 @@ import java.util.HashMap;
import java.util.Objects;
public class Minitools extends AppCompatActivity {
private final String TAG = "Minitools";
private final ArrayList<HashMap<String, String>> listmapForSelectMirrors = new ArrayList<>();
private Spinner spinnerselectmirror;
private String selectedMirrorCommand = "";
@ -56,7 +57,7 @@ public class Minitools extends AppCompatActivity {
setContentView(R.layout.activity_minitools);
// UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main));
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
@ -95,73 +96,63 @@ public class Minitools extends AppCompatActivity {
});
cleanup.setOnClickListener(v -> {
DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.clean_up), getResources().getString(R.string.clean_up_content), getResources().getString(R.string.clean_up), getResources().getString(R.string.cancel), true, R.drawable.cleaning_services_24px, true,
() -> {
VMManager.cleanUp();
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
restore.setVisibility(GONE);
cleanup.setVisibility(GONE);
}, null, null);
});
cleanup.setOnClickListener(v -> DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.clean_up), getResources().getString(R.string.clean_up_content), getResources().getString(R.string.clean_up), getResources().getString(R.string.cancel), true, R.drawable.cleaning_services_24px, true,
() -> {
VMManager.cleanUp();
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
restore.setVisibility(GONE);
cleanup.setVisibility(GONE);
}, null, null));
restore.setOnClickListener(v -> {
DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.restore), getResources().getString(R.string.restore_content), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.settings_backup_restore_24px, true,
() -> {
VMManager.restoreVMs();
UIUtils.oneDialog(getResources().getString(R.string.done), getResources().getString(R.string.restored) + " " + String.valueOf(VMManager.restoredVMs) + ".", true, false, Minitools.this);
restore.setVisibility(GONE);
}, null, null);
});
restore.setOnClickListener(v -> DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.restore), getResources().getString(R.string.restore_content), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.settings_backup_restore_24px, true,
() -> {
VMManager.restoreVMs();
UIUtils.oneDialog(getResources().getString(R.string.done), getResources().getString(R.string.restored) + " " + VMManager.restoredVMs + ".", true, false, Minitools.this);
restore.setVisibility(GONE);
}, null, null));
deleteallvm.setOnClickListener(v -> {
DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.delete_all_vm), getResources().getString(R.string.delete_all_vm_content), getResources().getString(R.string.delete_all), getResources().getString(R.string.cancel), true, R.drawable.delete_24px, true,
() -> {
VMManager.killallqemuprocesses(getApplicationContext());
FileUtils.deleteDirectory(AppConfig.vmFolder);
FileUtils.deleteDirectory(AppConfig.recyclebin);
FileUtils.deleteDirectory(AppConfig.romsdatajson);
File vDir = new File(AppConfig.maindirpath);
vDir.mkdirs();
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]");
cleanup.setVisibility(GONE);
restore.setVisibility(GONE);
deleteallvm.setVisibility(GONE);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
}, null, null);
});
deleteallvm.setOnClickListener(v -> DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.delete_all_vm), getResources().getString(R.string.delete_all_vm_content), getResources().getString(R.string.delete_all), getResources().getString(R.string.cancel), true, R.drawable.delete_24px, true,
() -> {
VMManager.killallqemuprocesses(getApplicationContext());
FileUtils.deleteDirectory(AppConfig.vmFolder);
FileUtils.deleteDirectory(AppConfig.recyclebin);
FileUtils.deleteDirectory(AppConfig.romsdatajson);
File vDir = new File(AppConfig.maindirpath);
vDir.mkdirs();
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]");
cleanup.setVisibility(GONE);
restore.setVisibility(GONE);
deleteallvm.setVisibility(GONE);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
}, null, null));
deleteall.setOnClickListener(v -> {
DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.delete_all), getResources().getString(R.string.delete_all_content), getResources().getString(R.string.delete_all), getResources().getString(R.string.cancel), true, R.drawable.delete_forever_24px, true,
() -> {
VMManager.killallqemuprocesses(getApplicationContext());
FileUtils.deleteDirectory(AppConfig.maindirpath);
File vDir = new File(AppConfig.maindirpath);
vDir.mkdirs();
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]");
cleanup.setVisibility(GONE);
restore.setVisibility(GONE);
deleteallvm.setVisibility(GONE);
deleteall.setVisibility(GONE);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
}, null, null);
});
deleteall.setOnClickListener(v -> DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.delete_all), getResources().getString(R.string.delete_all_content), getResources().getString(R.string.delete_all), getResources().getString(R.string.cancel), true, R.drawable.delete_forever_24px, true,
() -> {
VMManager.killallqemuprocesses(getApplicationContext());
FileUtils.deleteDirectory(AppConfig.maindirpath);
File vDir = new File(AppConfig.maindirpath);
vDir.mkdirs();
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]");
cleanup.setVisibility(GONE);
restore.setVisibility(GONE);
deleteallvm.setVisibility(GONE);
deleteall.setVisibility(GONE);
Toast.makeText(getApplicationContext(), getResources().getString(R.string.done), Toast.LENGTH_LONG).show();
}, null, null));
reinstallsystem.setOnClickListener(v -> {
DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.reinstall_system), getResources().getString(R.string.reinstall_system_content), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.system_update_24px, true,
() -> {
HomeActivity.isActivate = false;
AppConfig.needreinstallsystem = true;
VMManager.killallqemuprocesses(Minitools.this);
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/data");
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/distro");
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/usr");
Intent intent = new Intent();
intent.setClass(Minitools.this, SetupQemuActivity.class);
startActivity(intent);
finish();
}, null, null);
});
reinstallsystem.setOnClickListener(v -> DialogUtils.twoDialog(Minitools.this, getResources().getString(R.string.reinstall_system), getResources().getString(R.string.reinstall_system_content), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.system_update_24px, true,
() -> {
HomeActivity.isActivate = false;
AppConfig.needreinstallsystem = true;
VMManager.killallqemuprocesses(Minitools.this);
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/data");
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/distro");
FileUtils.deleteDirectory(getFilesDir().getAbsolutePath() + "/usr");
Intent intent = new Intent();
intent.setClass(Minitools.this, SetupQemuActivity.class);
startActivity(intent);
finish();
}, null, null));
spinnerselectmirror.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
@ -233,7 +224,7 @@ public class Minitools extends AppCompatActivity {
final TextView textViewLocation = _view.findViewById(R.id.textViewLocation);
textViewLocation.setText(_data.get((int) _position).get("location"));
textViewLocation.setText(_data.get(_position).get("location"));
return _view;
}
@ -260,7 +251,7 @@ public class Minitools extends AppCompatActivity {
out.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "copyAssetToFile: ", e);
return false;
}
}

View file

@ -6,7 +6,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.DragEvent;
import android.view.Menu;
@ -26,11 +25,10 @@ public class SetArchActivity extends AppCompatActivity implements View.OnClickLi
SetArchActivity activity;
ActivitySetArchBinding binding;
private static Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
UIUtils.edgeToEdge(this);
binding = ActivitySetArchBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@ -45,9 +43,7 @@ public class SetArchActivity extends AppCompatActivity implements View.OnClickLi
binding.bntimport.setOnClickListener(this);
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(v -> {
onBackPressed();
});
binding.toolbar.setNavigationOnClickListener(v -> finish());
binding.toolbar.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.roms_store) {
@ -62,42 +58,39 @@ public class SetArchActivity extends AppCompatActivity implements View.OnClickLi
// binding.buttongetcm.setText(getResources().getString(R.string.open));
// }
binding.bntimport.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
Log.i("Drag", "onDrag: " + event.getAction());
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
ClipDescription description = event.getClipDescription();
if (description != null) {
Log.d("DRAG", "MIME: " + description.getMimeType(0));
return true; // Accept to go to event DragEvent.ACTION_DROP
}
return false;
binding.bntimport.setOnDragListener((v, event) -> {
Log.i("Drag", "onDrag: " + event.getAction());
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
ClipDescription description = event.getClipDescription();
if (description != null) {
Log.d("DRAG", "MIME: " + description.getMimeType(0));
return true; // Accept to go to event DragEvent.ACTION_DROP
}
return false;
case DragEvent.ACTION_DROP:
ClipData clipData = event.getClipData();
if (clipData != null && clipData.getItemCount() > 0) {
Uri uri = clipData.getItemAt(0).getUri();
String filePath = FileUtils.getFilePathFromUri(getApplicationContext(), uri);
case DragEvent.ACTION_DROP:
ClipData clipData = event.getClipData();
if (clipData != null && clipData.getItemCount() > 0) {
Uri uri = clipData.getItemAt(0).getUri();
String filePath = FileUtils.getFilePathFromUri(getApplicationContext(), uri);
File file = new File(filePath);
File file = new File(filePath);
Intent intent = new Intent();
intent.setClass(getApplicationContext(), CustomRomActivity.class);
intent.putExtra("addromnow", "");
intent.putExtra("romextra", "");
intent.putExtra("romname", "");
intent.putExtra("romicon", "");
intent.putExtra("rompath", filePath);
intent.putExtra("romfilename", file.getName());
startActivity(intent);
finish();
}
return true;
}
return true;
Intent intent = new Intent();
intent.setClass(getApplicationContext(), CustomRomActivity.class);
intent.putExtra("addromnow", "");
intent.putExtra("romextra", "");
intent.putExtra("romname", "");
intent.putExtra("romicon", "");
intent.putExtra("rompath", filePath);
intent.putExtra("romfilename", file.getName());
startActivity(intent);
finish();
}
return true;
}
return true;
});
}

View file

@ -1,40 +1,15 @@
package com.vectras.vm;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import android.app.ProgressDialog;
import static android.os.Build.VERSION.SDK_INT;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.vectras.qemu.MainSettingsManager;
@ -42,20 +17,14 @@ import com.vectras.vm.home.HomeActivity;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vm.utils.UIUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
public class SplashActivity extends AppCompatActivity implements Runnable {
public static SplashActivity activity;
private final String TAG = "SplashActivity";
private static final String TAG = "SplashActivity";
@Override
protected void onCreate(Bundle bundle) {
@ -66,21 +35,12 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
UIUtils.setOnApplyWindowInsetsListener(findViewById(R.id.main));
setupFolders();
SharedPreferences prefs = getSharedPreferences(CREDENTIAL_SHARED_PREF, Context.MODE_PRIVATE);
try {
new Handler().postDelayed(activity, 1000);
} catch (Exception e) {
throw new RuntimeException(e);
}/*
boolean isAccessed = prefs.getBoolean("isFirstLaunch", false);
if (isAccessed && !checkConnection(activity)) {
new Handler().postDelayed(this, 3000);
} else {
Log.e(TAG, "Handler().postDelayed: ", e);
}
*/
//if (!checkPermission())
//requestPermission();
MainSettingsManager.setOrientationSetting(activity, 1);
setupFiles();
@ -100,38 +60,38 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
}
public void setupFiles() {
String filesDir = activity.getFilesDir().getAbsolutePath();
String nativeLibDir = activity.getApplicationInfo().nativeLibraryDir;
File tmpDir = new File(activity.getFilesDir(), "usr/tmp");
if (!tmpDir.isDirectory()) {
tmpDir.mkdirs();
FileUtils.chmod(tmpDir, 0771);
if (tmpDir.mkdirs()) {
FileUtils.chmod(tmpDir, 0771);
} else {
Log.e(TAG, "tmpDir: Directory creation failed!");
}
}
File vDir = new File(com.vectras.vm.AppConfig.maindirpath);
if (!vDir.exists()) {
vDir.mkdirs();
if (!vDir.mkdirs()) Log.e(TAG, com.vectras.vm.AppConfig.maindirpath + ": Directory creation failed!");
}
File distroDir = new File(filesDir + "/distro");
File distroDir = new File(AppConfig.internalDataDirPath + "distro");
if (!distroDir.exists()) {
distroDir.mkdirs();
if(!distroDir.mkdirs()) Log.e(TAG, "distro: Directory creation failed!");
}
File cvbiDir = new File(FileUtils.getExternalFilesDirectory(activity).getPath() + "/cvbi");
if (!cvbiDir.exists()) {
cvbiDir.mkdirs();
if(!cvbiDir.mkdirs()) Log.e(TAG, "cvbi: Directory creation failed!");
}
File sharedDir = new File(AppConfig.sharedFolder);
if (!sharedDir.exists()) {
sharedDir.mkdirs();
if(!sharedDir.mkdirs()) Log.e(TAG, AppConfig.sharedFolder + ": Directory creation failed!");
}
File downloadsDir = new File(AppConfig.downloadsFolder);
if (!downloadsDir.exists()) {
downloadsDir.mkdirs();
if(!downloadsDir.mkdirs()) Log.e(TAG, AppConfig.downloadsFolder+ ": Directory creation failed!");
}
File jsonFile = new File(AppConfig.maindirpath
@ -148,7 +108,7 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Create roms-data.json file failed: ", e);
}
com.vectras.qemu.utils.FileInstaller.installFiles(activity, true);
@ -166,187 +126,17 @@ public class SplashActivity extends AppCompatActivity implements Runnable {
}
}
public static String[] storage_permissions = {
WRITE_EXTERNAL_STORAGE,
READ_EXTERNAL_STORAGE
};
public String getPath(Uri uri) {
return com.vectras.vm.utils.FileUtils.getPath(this, uri);
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
if (checkPermission()) {
} else {
requestPermission();
Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
return;
}
}
/**
* CHECK WHETHER INTERNET CONNECTION IS AVAILABLE OR NOT
*/
public boolean checkConnection(Context context) {
final ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr != null) {
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
if (activeNetworkInfo != null) { // connected to the internet
// connected to the mobile provider's data plan
if (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
// connected to wifi
return true;
} else
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE;
}
}
return false;
}
class DownloadFileAsync extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... aurl) {
int count;
try {
URL url = new URL(aurl[0]);
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
Log.d(TAG, "Lenght of file: " + lenghtOfFile);
String fileName = "roms-" + MainSettingsManager.getArch(activity) + ".json";
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(getExternalFilesDir("data") + "/" + fileName);
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
publishProgress("" + (int) ((total * 100) / lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
}
return null;
}
protected void onProgressUpdate(String... progress) {
Log.d(TAG, progress[0]);
}
@Override
protected void onPostExecute(String unused) {
new Handler().postDelayed(activity, 3000);
}
}
private boolean checkPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int result = ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this,
permissions(),
1);
}
public static String[] permissions() {
String[] p;
p = storage_permissions;
return p;
}
private void copyAssetFile(String assetFileName, String destinationDirectory) {
new Thread(new Runnable() {
@Override
public void run() {
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(assetFileName);
File outFile = new File(destinationDirectory);
out = new FileOutputStream(outFile);
copyFile(in, out);
} catch (IOException e) {
Log.e("tag", "Failed to copy asset file: " + assetFileName, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// NOOP
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// NOOP
}
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
new Handler().postDelayed(this, 3000);
}
});
}
}
}).start();
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
public static void setupFolders() {
try {
StartVM.cache = activity.getCacheDir().getAbsolutePath();
} catch (Exception ignored) {
} catch (Exception e) {
Log.e(TAG, activity.getCacheDir().getAbsolutePath() + ": Directory creation failed!", e);
}
}
public static final String CREDENTIAL_SHARED_PREF = "settings_prefs";
@Override
public void run() {
String filesDir = activity.getFilesDir().getAbsolutePath();
SharedPreferences prefs = getSharedPreferences(CREDENTIAL_SHARED_PREF, Context.MODE_PRIVATE);
if ((new File(filesDir, "/distro/usr/local/bin/qemu-system-x86_64").exists()) || (new File(filesDir, "/distro/usr/bin/qemu-system-x86_64").exists())) {
if ((new File(AppConfig.internalDataDirPath, "distro/usr/local/bin/qemu-system-x86_64").exists()) || (new File(AppConfig.internalDataDirPath, "distro/usr/bin/qemu-system-x86_64").exists())) {
startActivity(new Intent(this, HomeActivity.class));
} else {
startActivity(new Intent(this, SetupQemuActivity.class));

View file

@ -1,7 +1,6 @@
package com.vectras.vm;
import android.app.Activity;
import android.content.Intent;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainSettingsManager;

View file

@ -4,20 +4,15 @@ import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static com.vectras.vm.utils.FileUtils.isFileExists;
import android.androidVNC.AbstractScaling;
import android.androidVNC.VncCanvas;
import android.androidVNC.VncCanvasActivity;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
@ -25,7 +20,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.GridLayoutManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
@ -38,7 +32,6 @@ import com.vectras.qemu.MainSettingsManager;
import com.vectras.qemu.MainVNCActivity;
import com.vectras.qemu.VNCConfig;
import com.vectras.qemu.utils.QmpClient;
import com.vectras.vm.MainRoms.AdapterMainRoms;
import com.vectras.vm.home.HomeActivity;
import com.vectras.vm.settings.VNCSettingsActivity;
import com.vectras.vm.utils.DialogUtils;
@ -73,6 +66,7 @@ public class VMManager {
public static String pendingDeviceID = "";
public static int restoredVMs = 0;
public static boolean isKeptSomeFiles = false;
public static boolean isQemuStopedWithError = false;
public static String latestUnsafeCommandReason = "";
public static String lastQemuCommand = "";
@ -96,8 +90,8 @@ public class VMManager {
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", finalJson);
finalJson = new Gson().toJson(mapForCreateNewVM);
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString(), "rom-data.json", finalJson.replace("\\u003d", "="));
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString(), "vmID.txt", Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString());
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")), "rom-data.json", finalJson.replace("\\u003d", "="));
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")), "vmID.txt", Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString());
}
public static void editVM(String name, String thumbnail, String drive, String arch, String cdrom, String params, int position) {
@ -127,8 +121,8 @@ public class VMManager {
finalJson = new Gson().toJson(listmapForCreateNewVM);
FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", finalJson);
finalJson = new Gson().toJson(mapForCreateNewVM);
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString(), "rom-data.json", finalJson.replace("\\u003d", "="));
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString(), "vmID.txt", Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString());
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")), "rom-data.json", finalJson.replace("\\u003d", "="));
FileUtils.writeToFile(AppConfig.maindirpath + "/roms/" + Objects.requireNonNull(mapForCreateNewVM.get("vmID")), "vmID.txt", Objects.requireNonNull(mapForCreateNewVM.get("vmID")).toString());
}
public static void deleteVMDialog(String _vmName, int _position, Activity _activity) {
@ -158,7 +152,7 @@ public class VMManager {
jSONArray.remove(_position);
Writer output = null;
Writer output;
File jsonFile = new File(AppConfig.maindirpath + "roms-data" + ".json");
output = new BufferedWriter(new FileWriter(jsonFile));
output.write(jSONArray.toString());
@ -187,7 +181,7 @@ public class VMManager {
@NonNull
public static String startRamdomVMID() {
String addAdb = "";
String addAdb;
Random random = new Random();
int randomAbc = random.nextInt(12);
if (randomAbc == 0) {
@ -215,7 +209,7 @@ public class VMManager {
} else {
addAdb = "l";
}
return addAdb + String.valueOf((long)(random.nextInt(65535)));
return addAdb + (long) (random.nextInt(65535));
}
public static int startRandomPort() {
@ -252,18 +246,18 @@ public class VMManager {
finalJson = new Gson().toJson(listmapForRemoveVM);
if (!pendingVMID.isEmpty()) {
int _startRepeat = 0;
String _currentVMIDToScan = "";
String _currentVMIDToScan;
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.txt").replace("\n", "");
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.txt").replace("\n", "");
if (!_currentVMIDToScan.isEmpty()) {
if (_currentVMIDToScan.equals(pendingVMID)) {
if (!finalJson.contains(_filelist.get((int)(_startRepeat)))) {
FileUtils.deleteDirectory(_filelist.get((int)(_startRepeat)));
if (!finalJson.contains(_filelist.get(_startRepeat))) {
FileUtils.deleteDirectory(_filelist.get(_startRepeat));
} else {
isKeptSomeFiles = true;
hideVMID(pendingVMID);
@ -281,17 +275,17 @@ public class VMManager {
public static void hideVMID(@NonNull String _vmID) {
if (!_vmID.isEmpty()) {
int _startRepeat = 0;
String _currentVMIDToScan = "";
String _currentVMIDToScan;
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.txt").replace("\n", "");
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.txt").replace("\n", "");
if (!_currentVMIDToScan.isEmpty()) {
if (_currentVMIDToScan.equals(_vmID)) {
FileUtils.moveAFile(_filelist.get((int)(_startRepeat)) + "/vmID.txt", _filelist.get((int)(_startRepeat)) + "/vmID.old.txt");
FileUtils.moveAFile(_filelist.get(_startRepeat) + "/vmID.txt", _filelist.get(_startRepeat) + "/vmID.old.txt");
}
}
}
@ -312,17 +306,17 @@ public class VMManager {
}
if (!pendingVMID.isEmpty()) {
int _startRepeat = 0;
String _currentVMIDToScan = "";
String _currentVMIDToScan;
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.txt").replace("\n", "");
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) {
_currentVMIDToScan = FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.txt").replace("\n", "");
if (!_currentVMIDToScan.isEmpty()) {
if (_currentVMIDToScan.equals(pendingVMID)) {
FileUtils.moveAFile(_filelist.get((int)(_startRepeat)) + "/vmID.txt", _filelist.get((int)(_startRepeat)) + "/vmID.old.txt");
FileUtils.moveAFile(_filelist.get(_startRepeat) + "/vmID.txt", _filelist.get(_startRepeat) + "/vmID.old.txt");
}
}
}
@ -340,11 +334,11 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (!isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) {
if (!finalJson.contains(_filelist.get((int) (_startRepeat)))) {
FileUtils.deleteDirectory(_filelist.get((int) (_startRepeat)));
if (!isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) {
if (!finalJson.contains(_filelist.get(_startRepeat))) {
FileUtils.deleteDirectory(_filelist.get(_startRepeat));
}
}
}
@ -362,38 +356,38 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (!isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.txt")) {
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/rom-data.json")) {
if (JSONUtils.isValidFromString(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/rom-data.json"))) {
if (!isFileExists(_filelist.get(_startRepeat) + "/vmID.txt")) {
if (isFileExists(_filelist.get(_startRepeat) + "/rom-data.json")) {
if (JSONUtils.isValidFromString(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"))) {
if (_resulttemp.toString().contains("}")) {
_resulttemp.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_resulttemp.append(",").append(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
} else {
_resulttemp = new StringBuilder(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_resulttemp = new StringBuilder(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
}
if (JSONUtils.isValidFromString(FileUtils.readAFile(AppConfig.maindirpath + "/roms-data.json").replaceAll("]", _resulttemp + "]"))) {
if (_result.toString().contains("}")) {
_result.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_result.append(",").append(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
} else {
_result = new StringBuilder(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_result = new StringBuilder(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
}
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt")) {
enableVMID(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt"));
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.old.txt")) {
enableVMID(FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.old.txt"));
} else {
FileUtils.writeToFile(_filelist.get((int)(_startRepeat)), "/vmID.txt", VMManager.idGenerator());
FileUtils.writeToFile(_filelist.get(_startRepeat), "/vmID.txt", VMManager.idGenerator());
}
restoredVMs++;
} else if (JSONUtils.isValidFromString(FileUtils.readAFile(AppConfig.maindirpath + "/roms-data.json").replaceAll("]", "," + _resulttemp + "]"))) {
if (_result.toString().contains("}")) {
_result.append(",").append(FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_result.append(",").append(FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
} else {
_result = new StringBuilder("," + FileUtils.readAFile(_filelist.get((int) (_startRepeat)) + "/rom-data.json"));
_result = new StringBuilder("," + FileUtils.readAFile(_filelist.get(_startRepeat) + "/rom-data.json"));
}
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt")) {
enableVMID(FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt"));
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.old.txt")) {
enableVMID(FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.old.txt"));
} else {
FileUtils.writeToFile(_filelist.get((int)(_startRepeat)), "/vmID.txt", VMManager.idGenerator());
FileUtils.writeToFile(_filelist.get(_startRepeat), "/vmID.txt", VMManager.idGenerator());
}
restoredVMs++;
} else {
@ -474,11 +468,11 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isFileExists(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt")) {
if (FileUtils.readAFile(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt").equals(_vmID)) {
FileUtils.moveAFile(_filelist.get((int)(_startRepeat)) + "/vmID.old.txt", _filelist.get((int)(_startRepeat)) + "/vmID.txt");
if (isFileExists(_filelist.get(_startRepeat) + "/vmID.old.txt")) {
if (FileUtils.readAFile(_filelist.get(_startRepeat) + "/vmID.old.txt").equals(_vmID)) {
FileUtils.moveAFile(_filelist.get(_startRepeat) + "/vmID.old.txt", _filelist.get(_startRepeat) + "/vmID.txt");
}
}
}
@ -500,10 +494,10 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(AppConfig.vmFolder, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (!finalJson.contains(Objects.requireNonNull(Uri.parse(_filelist.get((int) (_startRepeat))).getLastPathSegment()))) {
FileUtils.moveAFile(_filelist.get((int) (_startRepeat)), AppConfig.recyclebin + Uri.parse(_filelist.get((int) (_startRepeat))).getLastPathSegment());
if (!finalJson.contains(Objects.requireNonNull(Uri.parse(_filelist.get(_startRepeat)).getLastPathSegment()))) {
FileUtils.moveAFile(_filelist.get(_startRepeat), AppConfig.recyclebin + Uri.parse(_filelist.get(_startRepeat)).getLastPathSegment());
}
}
_startRepeat++;
@ -518,10 +512,10 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(_foderpath, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isADiskFile(_filelist.get((int)(_startRepeat)))) {
return _filelist.get((int)(_startRepeat));
if (isADiskFile(_filelist.get(_startRepeat))) {
return _filelist.get(_startRepeat);
}
}
_startRepeat++;
@ -534,7 +528,7 @@ public class VMManager {
public static boolean isADiskFile (@NonNull String _filepath) {
if (_filepath.contains(".")) {
String _getFileName = Objects.requireNonNull(Uri.parse(_filepath).getLastPathSegment()).toLowerCase();
String _getFileFormat = _getFileName.substring((int)(_getFileName.lastIndexOf(".") + 1), (int)(_getFileName.length()));
String _getFileFormat = _getFileName.substring(_getFileName.lastIndexOf(".") + 1);
return "qcow2,img,vhd,vhdx,vdi,qcow,vmdk,vpc".contains(_getFileFormat);
}
return false;
@ -546,10 +540,10 @@ public class VMManager {
ArrayList<String> _filelist = new ArrayList<>();
FileUtils.getAListOfAllFilesAndFoldersInADirectory(_foderpath, _filelist);
if (!_filelist.isEmpty()) {
for (int _repeat = 0; _repeat < (int)(_filelist.size()); _repeat++) {
for (int _repeat = 0; _repeat < _filelist.size(); _repeat++) {
if (_startRepeat < _filelist.size()) {
if (isAISOFile(_filelist.get((int)(_startRepeat)))) {
return _filelist.get((int)(_startRepeat));
if (isAISOFile(_filelist.get(_startRepeat))) {
return _filelist.get(_startRepeat);
}
}
_startRepeat++;
@ -562,7 +556,7 @@ public class VMManager {
public static boolean isAISOFile (@NonNull String _filepath) {
if (_filepath.contains(".")) {
String _getFileName = Objects.requireNonNull(Uri.parse(_filepath).getLastPathSegment()).toLowerCase();
String _getFileFormat = _getFileName.substring((int)(_getFileName.lastIndexOf(".") + 1), (int)(_getFileName.length()));
String _getFileFormat = _getFileName.substring(_getFileName.lastIndexOf(".") + 1);
return "iso".contains(_getFileFormat);
}
return false;
@ -586,10 +580,15 @@ public class VMManager {
}
public static boolean isExecutedCommandError(@NonNull String _command, String _result, Activity _activity) {
if (!_command.contains("qemu-system"))
if (!_command.contains("qemu-system")) {
isQemuStopedWithError = false;
return false;
if (_command.contains("qemu-system") && _result.contains("Killed"))
}
if (_command.contains("qemu-system") && _result.contains("Killed")) {
isQemuStopedWithError = true;
return true;
}
//Error code: PROOT_IS_MISSING_0
if (_result.contains("proot\": error=2,")) {
DialogUtils.twoDialog(_activity, _activity.getResources().getString(R.string.problem_has_been_detected), _activity.getResources().getString(R.string.error_PROOT_IS_MISSING_0), _activity.getString(R.string.continuetext), _activity.getString(R.string.cancel), true, R.drawable.build_24px, true,
@ -604,10 +603,12 @@ public class VMManager {
_activity.finish();
},
null, null);
isQemuStopedWithError = true;
return true;
} else if (_result.contains(") exists") && _result.contains("drive with bus")) {
//Error code: DRIVE_INDEX_0_EXISTS
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_DRIVE_INDEX_0_EXISTS) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.hard_drive_24px, true,null, null);
isQemuStopedWithError = true;
return true;
} else if (_result.contains("gtk initialization failed") || _result.contains("x11 not available")) {
//Error code: X11_NOT_AVAILABLE
@ -617,13 +618,28 @@ public class VMManager {
DialogUtils.oneDialog(_activity, _activity.getString(R.string.done), _activity.getString(R.string.switched_to_VNC), _activity.getString(R.string.ok),true, R.drawable.check_24px, true,null, null);
},
null, null);
isQemuStopedWithError = true;
return true;
} else if (_result.contains("No such file or directory")) {
//Error code: NO_SUCH_FILE_OR_DIRECTORY
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_NO_SUCH_FILE_OR_DIRECTORY) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
} else if (_result.contains("another process using")) {
//Error code: ANOTHER_PROCESS_USING_IMAGE
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.error_ANOTHER_PROCESS_USING_IMAGE) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.file_copy_24px, true,null, null);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
} else if (_command.contains("qemu-system") && _result.contains("qemu-system")) {
//Error code: UNKNOW_ERROR
DialogUtils.oneDialog(_activity, _activity.getString(R.string.problem_has_been_detected), _activity.getString(R.string.vm_could_not_be_run_content) + "\n\n" + _result, _activity.getString(R.string.ok),true, R.drawable.error_96px, true,null, null);
_activity.stopService(new Intent(_activity, MainService.class));
isQemuStopedWithError = true;
return true;
} else {
isQemuStopedWithError = false;
return false;
}
}
@ -721,10 +737,9 @@ public class VMManager {
return true;
}
public static boolean isThisVMRunning(Activity activity, String intemExtra, String itemPath) {
Terminal vterm = new Terminal(activity);
vterm.executeShellCommand2("ps -e", false, activity);
if (AppConfig.temporaryLastedTerminalOutput.contains(intemExtra) && AppConfig.temporaryLastedTerminalOutput.contains(itemPath)) {
public static boolean isVMRunning(Activity activity, String vmID) {
String result = Terminal.executeShellCommandWithResult("ps -e", activity);
if (result.contains(Config.getCacheDir() + "/" + vmID + "/qmpsocket")) {
Log.d("VMManager.isThisVMRunning", "Yes");
return true;
} else {
@ -774,7 +789,7 @@ public class VMManager {
public static void killcurrentqemuprocess(Activity activity) {
Terminal vterm = new Terminal(activity);
String env = "killall -9 ";
String env = "killall -15 ";
switch (MainSettingsManager.getArch(activity)) {
case "ARM64":
env += "qemu-system-aarch64";
@ -794,10 +809,10 @@ public class VMManager {
public static void killallqemuprocesses(Context context) {
Terminal vterm = new Terminal(context);
vterm.executeShellCommand2("killall -9 qemu-system-i386", false, null);
vterm.executeShellCommand2("killall -9 qemu-system-x86_64", false, null);
vterm.executeShellCommand2("killall -9 qemu-system-aarch64", false, null);
vterm.executeShellCommand2("killall -9 qemu-system-ppc", false, null);
vterm.executeShellCommand2("killall -15 qemu-system-i386", false, null);
vterm.executeShellCommand2("killall -15 qemu-system-x86_64", false, null);
vterm.executeShellCommand2("killall -15 qemu-system-aarch64", false, null);
vterm.executeShellCommand2("killall -15 qemu-system-ppc", false, null);
}
public static void shutdownCurrentVM() {
@ -1125,18 +1140,18 @@ public class VMManager {
}
}
public static void setVNCPasswordWithDelay(String _password, Activity _activity) {
public static void setVNCPasswordWithDelay(String _password) {
new Thread(() -> {
try {
Thread.sleep(1000);
setVNCPassword(_password, _activity);
setVNCPassword(_password);
} catch (InterruptedException e) {
Log.d(TAG, "setVNCPasswordWithDelay: " + e.getMessage());
}
}).start();
}
public static void setVNCPassword(String _password, Activity _activity) {
public static void setVNCPassword(String _password) {
String _result = QmpClient.sendCommand(changeVNCPasswordQMPCommand(_password));
if (isQMPCommandSuccess(_result)) {
Log.d(TAG, "setVNCPassword: Success");
@ -1197,18 +1212,4 @@ public class VMManager {
|| _qemuCommand.contains("-M pc-q35")
|| _qemuCommand.contains("-machine pc-q35");
}
public static boolean checkSharedFolder() { //TODO: not work idk why
File folder = new File(AppConfig.sharedFolder);
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile() && file.length() > 500 * 1024 * 1024) { // 500MB
return true;
}
}
}
return false;
}
}

View file

@ -1,52 +1,37 @@
package com.vectras.vm;
import android.Manifest;
import android.app.Activity;
import android.app.Application;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import com.google.android.material.color.DynamicColors;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vm.utils.PackageUtils;
import com.vectras.vterm.Terminal;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@ -55,20 +40,17 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
public class VectrasApp extends Application {
@ -238,13 +220,9 @@ public class VectrasApp extends Application {
} catch (final Throwable e) {
e.printStackTrace();
if (isRunning.get()) {
MAIN_HANDLER.post(new Runnable() {
@Override
public void run() {
//VectrasStatus.logError("<font color='red'>[E] >"+ mContext.getApplicationContext().toString() +e.getMessage()+"</font>");
}
});
MAIN_HANDLER.post(() -> {
//VectrasStatus.logError("<font color='red'>[E] >"+ mContext.getApplicationContext().toString() +e.getMessage()+"</font>");
});
} else {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
@ -318,9 +296,9 @@ public class VectrasApp extends Application {
head.put("App Version", String.format("%s (%d)", versionName, versionCode));
head.put("Kernel", getKernel());
head.put("Support Abis",
Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null
? Arrays.toString(Build.SUPPORTED_ABIS)
: "unknown");
Build.SUPPORTED_ABIS != null
? Arrays.toString(Build.SUPPORTED_ABIS)
: "unknown");
head.put("Fingerprint", Build.FINGERPRINT);
StringBuilder builder = new StringBuilder();
@ -343,7 +321,7 @@ public class VectrasApp extends Application {
String time = DATE_FORMAT.format(new Date());
File file = new File(mCrashDir, "crash_" + time + ".txt");
try {
write(file, log.getBytes("UTF-8"));
write(file, log.getBytes(StandardCharsets.UTF_8));
} catch (Throwable e) {
e.printStackTrace();
}
@ -434,6 +412,7 @@ public class VectrasApp extends Application {
private void setupAppConfig(Context _context) {
AppConfig.vectrasVersion = PackageUtils.getThisVersionName(_context);
AppConfig.vectrasVersionCode = PackageUtils.getThisVersionCode(_context);
AppConfig.internalDataDirPath = getFilesDir().getPath() + "/";
AppConfig.basefiledir = AppConfig.datadirpath(_context) + "/.qemu/";
AppConfig.maindirpath = FileUtils.getExternalFilesDirectory(_context).getPath() + "/";
AppConfig.sharedFolder = AppConfig.maindirpath + "SharedFolder/";

View file

@ -216,11 +216,13 @@ public class HomeActivity extends AppCompatActivity implements RomStoreFragment.
public void handleOnBackPressed() {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START);
} else {
} else if (MainSettingsManager.getQuickStart(HomeActivity.this)){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
finish();
}
}
});

View file

@ -6,16 +6,17 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.appbar.AppBarLayout;
import com.bumptech.glide.Glide;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainSettingsManager;
@ -34,20 +35,20 @@ import com.vectras.vm.utils.ServiceUtils;
import java.io.File;
public class HomeStartVM {
public static final String TAG = "HomeStartVM";
public static AlertDialog progressDialog;
public static boolean skipIDEwithARM64DialogInStartVM = false;
public static final Handler handlerForLaunch = new Handler(Looper.getMainLooper());
public static Runnable tickForLaunch = null;
public static void startNow(
Activity activity,
String vmName,
String env,
String itemExtra,
String itemPath,
AppBarLayout appbar,
LinearLayout extVncLayout
String vmID,
String thumbnailFile
) {
File romDir = new File(Config.getCacheDir() + "/" + Config.vmID);
File romDir = new File(Config.getCacheDir() + "/" + vmID);
if (!romDir.exists()) {
if (!romDir.mkdirs()) {
DialogUtils.oneDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.vm_cache_dir_failed_to_create_content), activity.getString(R.string.ok), true, R.drawable.warning_48px, true, null, null);
@ -81,7 +82,7 @@ public class HomeStartVM {
VMManager.lastQemuCommand = env;
if (VMManager.isThisVMRunning(activity, itemExtra, itemPath)) {
if (VMManager.isVMRunning(activity, vmID)) {
Toast.makeText(activity, "This VM is already running.", Toast.LENGTH_LONG).show();
if (MainSettingsManager.getVmUi(activity).equals("VNC"))
activity.startActivity(new Intent(activity, MainVNCActivity.class));
@ -93,7 +94,7 @@ public class HomeStartVM {
if (AppConfig.getSetupFiles().contains("arm") && !AppConfig.getSetupFiles().contains("arm64")) {
if (env.contains("tcg,thread=multi")) {
DialogUtils.twoDialog(activity, activity.getResources().getString(R.string.problem_has_been_detected), activity.getResources().getString(R.string.can_not_use_mttcg), activity.getString(R.string.ok), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true,
() -> startNow(activity, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), itemExtra, itemPath, appbar, extVncLayout), null, null);
() -> startNow(activity, vmName, env.replace("tcg,thread=multi", "tcg,thread=single"), vmID, thumbnailFile), null, null);
return;
}
}
@ -102,7 +103,7 @@ public class HomeStartVM {
DialogUtils.twoDialog(activity, activity.getString(R.string.problem_has_been_detected), activity.getString(R.string.you_cannot_use_IDE_hard_drive_type_with_ARM64), activity.getString(R.string.continuetext), activity.getString(R.string.cancel), true, R.drawable.warning_48px, true,
() -> {
skipIDEwithARM64DialogInStartVM = true;
startNow(activity, vmName, env, itemExtra, itemPath, appbar, extVncLayout);
startNow(activity, vmName, env, vmID, thumbnailFile);
}, null, null);
return;
} else if (skipIDEwithARM64DialogInStartVM) {
@ -126,60 +127,61 @@ public class HomeStartVM {
return;
}
showProgressDialog(activity, activity.getString(R.string.booting_up));
Handler handler = new Handler();
handler.postDelayed(
() -> {
if (ServiceUtils.isServiceRunning(activity, MainService.class)) {
MainService.startCommand(env, activity);
} else {
Intent serviceIntent = new Intent(activity, MainService.class);
MainService.env = env;
MainService.CHANNEL_ID = vmName;
MainService.activity = activity;
if (SDK_INT >= Build.VERSION_CODES.O) {
activity.startForegroundService(serviceIntent);
} else {
activity.startService(serviceIntent);
}
}
showProgressDialog(activity, vmName, thumbnailFile);
VMManager.isQemuStopedWithError = false;
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
if (MainSettingsManager.getVncExternal(activity)) {
if (extVncLayout != null) extVncLayout.setVisibility(View.VISIBLE);
if (appbar != null) appbar.setExpanded(true);
progressDialog.dismiss();
} else {
Handler handler1 = new Handler();
handler1.postDelayed(
() -> {
MainVNCActivity.started = true;
activity.startActivity(
new Intent(
activity, MainVNCActivity.class));
progressDialog.dismiss();
},
2000);
}
if (ServiceUtils.isServiceRunning(activity, MainService.class)) {
MainService.startCommand(env, activity);
} else {
Intent serviceIntent = new Intent(activity, MainService.class);
MainService.env = env;
MainService.CHANNEL_ID = vmName;
MainService.activity = activity;
if (SDK_INT >= Build.VERSION_CODES.O) {
activity.startForegroundService(serviceIntent);
} else {
activity.startService(serviceIntent);
}
}
tickForLaunch = new Runnable() {
@Override
public void run() {
if (VMManager.isQemuStopedWithError || FileUtils.isFileExists(Config.getLocalQMPSocketPath())) {
handlerForLaunch.removeCallbacks(this);
progressDialog.dismiss();
//If Qemu doesn't crash and finish then launch.
if (!VMManager.isQemuStopedWithError) {
if (MainSettingsManager.getVmUi(activity).equals("VNC")) {
if (MainSettingsManager.getVncExternal(activity)) {
Config.currentVNCServervmID = vmID;
DialogUtils.oneDialog(activity, activity.getString(R.string.vnc_server), activity.getString(R.string.running_vm_with_vnc_server_content) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(activity)) + 5900) + ".", activity.getString(R.string.ok), true, R.drawable.cast_24px, true, null, null);
} else {
MainVNCActivity.started = true;
activity.startActivity(new Intent(activity, MainVNCActivity.class));
}
// } else if (MainSettingsManager.getVmUi(activity).equals("SPICE")) {
// //This feature is not available yet.
} else if (MainSettingsManager.getVmUi(activity).equals("X11")) {
Handler handler1 = new Handler();
handler1.postDelayed(
() -> {
progressDialog.dismiss();
DisplaySystem.launchX11(activity, false);
},
3000);
} else if (MainSettingsManager.getVmUi(activity).equals("X11")) {
DisplaySystem.launchX11(activity, false);
}
Log.i(TAG, "Virtual machine running.");
}
if (MainSettingsManager.getVncExternal(activity)) {
Config.currentVNCServervmID = Config.vmID;
DialogUtils.oneDialog(activity, activity.getString(R.string.vnc_server), activity.getString(R.string.running_vm_with_vnc_server_content) + " " + (Integer.parseInt(MainSettingsManager.getVncExternalDisplay(activity)) + 5900) + ".", activity.getString(R.string.ok), true, R.drawable.cast_24px, true, null, null);
}
},
2000);
skipIDEwithARM64DialogInStartVM = false;
tickForLaunch = null;
return;
}
handlerForLaunch.postDelayed(this, 500);
}
};
handlerForLaunch.postDelayed(tickForLaunch, 1000);
String[] params = env.split("\\s+");
VectrasStatus.logInfo("Params:");
Log.d("HomeStartVM", "Params:");
@ -190,10 +192,29 @@ public class HomeStartVM {
}
public static void showProgressDialog(Activity activity, String _content) {
View progressView = LayoutInflater.from(activity).inflate(R.layout.dialog_progress_style, null);
TextView progress_text = progressView.findViewById(R.id.progress_text);
progress_text.setText(_content);
public static void showProgressDialog(Activity activity, String _content, String thumbnailFile) {
View progressView = LayoutInflater.from(activity).inflate(R.layout.dialog_start_vm, null);
TextView tvVMName = progressView.findViewById(R.id.vm_name);
tvVMName.setText(_content);
if (thumbnailFile != null) {
ImageView ivThumbnail = progressView.findViewById(R.id.iv_thumbnail);
if (thumbnailFile.isEmpty()){
VMManager.setIconWithName(ivThumbnail, _content);
} else {
if (FileUtils.isFileExists(thumbnailFile)) {
Glide.with(activity.getApplicationContext())
.load(new File(thumbnailFile))
.placeholder(R.drawable.ic_computer_180dp_with_padding)
.error(R.drawable.ic_computer_180dp_with_padding)
.into(ivThumbnail);
} else {
VMManager.setIconWithName(ivThumbnail, _content);
}
}
}
progressDialog = new MaterialAlertDialogBuilder(activity, R.style.CenteredDialogTheme)
.setView(progressView)
.setCancelable(false)

View file

@ -3,6 +3,7 @@ package com.vectras.vm.home.core;
import android.app.Activity;
import android.widget.Toast;
import com.vectras.qemu.Config;
import com.vectras.vm.AppConfig;
import com.vectras.vm.R;
import com.vectras.vm.StartVM;
@ -47,7 +48,8 @@ public class PendingCommand {
} else {
com.vectras.vm.StartVM.cdrompath = "";
String env = StartVM.env(activity, AppConfig.pendingCommand, "", "1");
HomeStartVM.startNow(activity, "Quick run", env, AppConfig.pendingCommand, "", null, null);
Config.vmID = VMManager.idGenerator();
HomeStartVM.startNow(activity, "Quick run", env, Config.vmID, null);
VMManager.lastQemuCommand = AppConfig.pendingCommand;
}
}

View file

@ -198,7 +198,7 @@ public class SystemMonitorFragment extends Fragment {
binding.tvQemuarch.setText(getString(R.string.arch) + " " + currentArch + ".");
executor.execute(() -> {
String result = Terminal.executeShellCommandWithResult("ps -eo command", requireActivity());
String result = Terminal.executeShellCommandWithResult("ps -e command", requireActivity());
requireActivity().runOnUiThread(() -> {
if (!result.isEmpty()) {
switch (currentArch) {

View file

@ -75,7 +75,7 @@ public class VmsHomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
Config.vmID = current.vmID;
String env = StartVM.env(activity, current.itemExtra, current.itemPath, "");
HomeStartVM.startNow(activity, current.itemName, env, current.itemExtra, current.itemPath, null, null);
HomeStartVM.startNow(activity, current.itemName, env, current.vmID, current.itemIcon);
});
myHolder.cdRoms.setOnLongClickListener(v -> {

View file

@ -6,6 +6,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
@ -38,6 +39,8 @@ public class DialogUtils {
icon.setVisibility(View.GONE);
}
if (UIUtils.isUsingThemeNightMode()) positiveButton.setTextColor(Color.WHITE);
title.setText(_title);
content.setText(_message);
@ -81,6 +84,11 @@ public class DialogUtils {
icon.setVisibility(View.GONE);
}
if (UIUtils.isUsingThemeNightMode()) {
positiveButton.setTextColor(Color.WHITE);
negativeButton.setTextColor(Color.WHITE);
}
title.setText(_title);
content.setText(_message);
@ -135,6 +143,12 @@ public class DialogUtils {
title.setText(_title);
content.setText(_message);
if (UIUtils.isUsingThemeNightMode()) {
positiveButton.setTextColor(Color.WHITE);
negativeButton.setTextColor(Color.WHITE);
neutralButton.setTextColor(Color.WHITE);
}
positiveButton.setText(_textPositiveButton);
negativeButton.setText(_textNegativeButton);
neutralButton.setText(_textNeutralButton);

View file

@ -5,6 +5,7 @@ import android.app.Activity;
import androidx.activity.ComponentActivity;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
@ -499,4 +500,9 @@ public class UIUtils {
return insets;
});
}
public static boolean isUsingThemeNightMode() {
int nightMode = AppCompatDelegate.getDefaultNightMode();
return nightMode == AppCompatDelegate.MODE_NIGHT_YES;
}
}

View file

@ -119,11 +119,11 @@ public class Terminal {
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm",
"-b", AppConfig.internalDataDirPath + "distro/root:/dev/shm",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp",
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
"-w", "/root",
"/bin/sh",
"--login"
@ -215,11 +215,11 @@ public class Terminal {
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm",
"-b", AppConfig.internalDataDirPath + "distro/root:/dev/shm",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp",
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
"-w", "/root",
"/bin/sh",
"--login"// The shell to execute inside PRoot
@ -317,11 +317,11 @@ public class Terminal {
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm",
"-b", AppConfig.internalDataDirPath + "distro/root:/dev/shm",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp",
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
"-w", "/root",
"/bin/sh",
"--login"
@ -397,11 +397,11 @@ public class Terminal {
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm",
"-b", AppConfig.internalDataDirPath + "distro/root:/dev/shm",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp",
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
"-w", "/root",
"/bin/sh",
"--login"
@ -513,11 +513,11 @@ public class Terminal {
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/data/data/com.vectras.vm/files/distro/root:/dev/shm",
"-b", AppConfig.internalDataDirPath + "distro/root:/dev/shm",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-b", "/data/data/com.vectras.vm/files/usr/tmp:/tmp",
"-b", AppConfig.internalDataDirPath + "usr/tmp:/tmp",
"-w", "/root",
"/bin/sh",
"--login"
@ -558,7 +558,7 @@ public class Terminal {
errors.append(Log.getStackTraceString(e));
} finally {
// Dismiss ProgressDialog on the main thread
new Handler(Looper.getMainLooper()).post(() -> progressDialog.dismiss());
new Handler(Looper.getMainLooper()).post(progressDialog::dismiss);
// Return the output and errors via callback on the main thread
String finalOutput = output.toString();

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="M480,880Q398,880 325,848.5Q252,817 197.5,762.5Q143,708 111.5,635Q80,562 80,480Q80,397 111.5,324.5Q143,252 197.5,197.5Q252,143 325,111.5Q398,80 480,80Q563,80 635.5,111.5Q708,143 762.5,197.5Q817,252 848.5,324.5Q880,397 880,480Q880,562 848.5,635Q817,708 762.5,762.5Q708,817 635.5,848.5Q563,880 480,880ZM480,798Q506,762 525,723Q544,684 556,640L404,640Q416,684 435,723Q454,762 480,798ZM376,782Q358,749 344.5,713.5Q331,678 322,640L204,640Q233,690 276.5,727Q320,764 376,782ZM584,782Q640,764 683.5,727Q727,690 756,640L638,640Q629,678 615.5,713.5Q602,749 584,782ZM170,560L306,560Q303,540 301.5,520.5Q300,501 300,480Q300,459 301.5,439.5Q303,420 306,400L170,400Q165,420 162.5,439.5Q160,459 160,480Q160,501 162.5,520.5Q165,540 170,560ZM386,560L574,560Q577,540 578.5,520.5Q580,501 580,480Q580,459 578.5,439.5Q577,420 574,400L386,400Q383,420 381.5,439.5Q380,459 380,480Q380,501 381.5,520.5Q383,540 386,560ZM654,560L790,560Q795,540 797.5,520.5Q800,501 800,480Q800,459 797.5,439.5Q795,420 790,400L654,400Q657,420 658.5,439.5Q660,459 660,480Q660,501 658.5,520.5Q657,540 654,560ZM638,320L756,320Q727,270 683.5,233Q640,196 584,178Q602,211 615.5,246.5Q629,282 638,320ZM404,320L556,320Q544,276 525,237Q506,198 480,162Q454,198 435,237Q416,276 404,320ZM204,320L322,320Q331,282 344.5,246.5Q358,211 376,178Q320,196 276.5,233Q233,270 204,320Z"/>
</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="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,320L160,320L160,720Q160,720 160,720Q160,720 160,720ZM300,680L244,624L347,520L243,416L300,360L460,520L300,680ZM480,680L480,600L720,600L720,680L480,680Z"/>
</vector>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_thumbnail"
android:layout_width="120dp"
android:layout_height="120dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_computer_180dp_with_padding"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/vm_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/vm_action_create_new"
android:textAppearance="?attr/textAppearanceBodyLarge"
android:singleLine="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingVertical="8dp"
android:text="@string/booting_up" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:indeterminate="true" />
</LinearLayout>
</LinearLayout>

View file

@ -30,7 +30,7 @@
android:title="@string/alpine_desktop"/>
<item
android:id="@+id/navigation_item_terminal"
android:icon="@drawable/round_terminal_24"
android:icon="@drawable/terminal_24px"
android:title="@string/terminal"/>
<item
android:id="@+id/navigation_item_view_logs"
@ -50,7 +50,7 @@
android:title="@string/open_main_folder"/>
<item
android:id="@+id/navigation_item_website"
android:icon="@drawable/round_public_24"
android:icon="@drawable/language_24px"
android:title="@string/vectras_website" />
<item
android:id="@+id/navigation_item_donate"

View file

@ -3,7 +3,7 @@
<string name="app_name">Vectras VM</string>
<!--======================VECTRAS STRINGS====================-->
<string name="app_version" translatable="false">v2.9.5.12-3dfx</string>
<string name="app_version" translatable="false">v2.9.5.13-3dfx</string>
<string name="qemu_version" translatable="false">Stable</string>
<string name="str_home">Home</string>
<string name="str_logger">Logger</string>
@ -569,6 +569,11 @@
<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>
<string name="vm_could_not_be_run_content">An error occurred and the virtual machine could not be run.</string>
<string name="error_ANOTHER_PROCESS_USING_IMAGE">An error occurred and the virtual machine could not be started. Another process is using a file that this virtual machine also needs. Find and terminate that process.</string>
<string name="could_not_create_dir_to_save_cvbi_content">Something went wrong. Could not create directory to save cvbi file.</string>
<string name="quick_start">Quick start</string>
<string name="quick_start_description">To start up faster the next time you open Vectras VM if you don\'t remove it from multitasking.</string>
<!--======================TERMUX STRINGS====================-->

View file

@ -36,6 +36,16 @@
android:title="@string/copy_file"
app:icon="@drawable/file_copy_24px" />
<SwitchPreferenceCompat
android:id="@+id/quickstart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="true"
android:key="quickStart"
android:summary="@string/quick_start_description"
android:title="@string/quick_start"
app:icon="@drawable/power_settings_new_24px" />
<ListPreference
android:key="language"
android:title="@string/language"

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,v2.9.5.12-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,v2.9.5.13-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.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",
"versionNameBeta":"v2.9.5.13-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,v2.9.5.13-3dfx",
"sizeBeta": "41 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>v2.9.5.12-3dfx</h2>Bugs fixed.",
"MessageBeta": "<h2>v2.9.5.13-3dfx</h2>Bugs fixed.",
"cancellableBeta": true
}