Vectras-VM-Android/app/src/main/java/com/vectras/vm/SetupQemuActivity.java
2025-03-08 12:48:59 +07:00

912 lines
39 KiB
Java

package com.vectras.vm;
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static android.content.Intent.ACTION_VIEW;
import com.termux.app.TermuxService;
import static com.vectras.vm.utils.UIUtils.UIAlert;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.Manifest;
import android.widget.BaseAdapter;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.button.MaterialButton;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.vectras.qemu.MainSettingsManager;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vterm.view.ZoomableTextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
public class SetupQemuActivity extends AppCompatActivity implements View.OnClickListener {
Activity activity;
private final String TAG = "SetupQemuActivity";
ZoomableTextView vterm;
MaterialButton inBtn;
ProgressBar progressBar;
TextView title;
LinearLayout linearload;
LinearLayout linearcannotconnecttoserver;
Button buttontryconnectagain;
LinearLayout linearsimplesetupui;
LinearLayout linearstartsetup;
MaterialButton buttonautosetup;
MaterialButton buttonmanualsetup;
LinearLayout linearsettingup;
TextView textviewsettingup;
LinearLayout linearsetupfailed;
MaterialButton buttonsetuptryagain;
MaterialButton buttonsetupshowlog;
TextView textviewshowadvancedsetup;
TextView textviewhideadvancedsetup;
Spinner spinnerselectmirror;
AlertDialog alertDialog;
private boolean settingup = false;
private boolean libprooterror = false;
private RequestNetwork net;
private RequestNetwork.RequestListener _net_request_listener;
private String contentJSON = "";
private HashMap<String, Object> mmap = new HashMap<>();
private String bootstrapfilelink = "";
private ArrayList<HashMap<String, String>> listmapForSelectMirrors = new ArrayList<>();
private String selectedMirrorCommand = "";
private String selectedMirrorLocation = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setup_qemu);
activity = this;
linearload = findViewById(R.id.linearload);
linearcannotconnecttoserver = findViewById(R.id.linearcannotconnecttoserver);
buttontryconnectagain = findViewById(R.id.buttontryconnectagain);
linearsimplesetupui = findViewById(R.id.linearsimplesetupui);
linearstartsetup = findViewById(R.id.linearstartsetup);
buttonautosetup = findViewById(R.id.buttonautosetup);
buttonmanualsetup = findViewById(R.id.buttonmanualsetup);
linearsettingup = findViewById(R.id.linearsettingup);
textviewsettingup = findViewById(R.id.textviewsettingup);
linearsetupfailed = findViewById(R.id.linearsetupfailed);
buttonsetuptryagain = findViewById(R.id.buttonsetuptryagain);
buttonsetupshowlog = findViewById(R.id.buttonsetupshowlog);
textviewshowadvancedsetup = findViewById(R.id.textviewshowadvancedsetup);
textviewhideadvancedsetup = findViewById(R.id.textviewhideadvancedsetup);
spinnerselectmirror = findViewById(R.id.spinnerselectmirror);
buttontryconnectagain.setOnClickListener(this);
buttonautosetup.setOnClickListener(this);
buttonmanualsetup.setOnClickListener(this);
buttonsetuptryagain.setOnClickListener(this);
buttonsetupshowlog.setOnClickListener(this);
textviewshowadvancedsetup.setOnClickListener(this);
textviewhideadvancedsetup.setOnClickListener(this);
progressBar = findViewById(R.id.progressBar);
vterm = findViewById(R.id.tvTerminalOutput);
inBtn = findViewById(R.id.btnInstall);
title = findViewById(R.id.title);
inBtn.setOnClickListener(this);
setupSpiner();
tarPath = getExternalFilesDir("data") + "/data.tar.gz";
VectrasApp.prepareDataForAppConfig(activity);
spinnerselectmirror.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedMirrorCommand = Objects.requireNonNull(listmapForSelectMirrors.get(position).get("mirror"));
selectedMirrorLocation = Objects.requireNonNull(listmapForSelectMirrors.get(position).get("location"));
MainSettingsManager.setSelectedMirror(activity, position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
net = new RequestNetwork(this);
_net_request_listener = new RequestNetwork.RequestListener() {
@Override
public void onResponse(String tag, String response, HashMap<String, Object> responseHeaders) {
linearload.setVisibility(View.GONE);
contentJSON = response;
if (VectrasApp.checkJSONMapIsNormalFromString(contentJSON)) {
mmap.clear();
mmap= new Gson().fromJson(contentJSON, new TypeToken<HashMap<String, Object>>(){}.getType());
if(mmap.containsKey("arm64") && mmap.containsKey("x86_64")) {
if (Build.SUPPORTED_ABIS[0].contains("arm64")) {
bootstrapfilelink = mmap.get("arm64").toString();
} else {
bootstrapfilelink = mmap.get("x86_64").toString();
}
linearcannotconnecttoserver.setVisibility(View.GONE);
}
if (AppConfig.needreinstallsystem) {
AppConfig.needreinstallsystem = false;
if (!MainSettingsManager.getsetUpWithManualSetupBefore(SetupQemuActivity.this)) {
if (AppConfig.getSetupFiles().contains("arm64-v8a") || AppConfig.getSetupFiles().contains("x86_64")) {
setupVectras64();
} else {
setupVectras32();
}
textviewsettingup.setText(getResources().getString(R.string.reinstalling));
simpleSetupUIControler(1);
}
}
} else {
linearload.setVisibility(View.GONE);
}
}
@Override
public void onErrorResponse(String tag, String message) {
linearload.setVisibility(View.GONE);
}
};
net.startRequestNetwork(RequestNetworkController.GET,AppConfig.bootstrapfileslink,"anbui",_net_request_listener);
String filesDir = activity.getFilesDir().getAbsolutePath();
File distroDir = new File(filesDir + "/distro");
File binDir = new File(distroDir + "/bin");
if (!binDir.exists()) {
extractBootstraps();
}
}
public void extractBootstraps() {
String filesDir = getFilesDir().getAbsolutePath();
String abi = getDeviceAbi();
String assetPath = "bootstrap/" + abi + ".tar";
String extractedFilePath = filesDir + "/" + abi + ".tar";
ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Extracting data...");
progressDialog.setCancelable(false);
progressDialog.show();
new AsyncTask<Void, Void, Boolean>() {
String errorMessage = null;
@Override
protected Boolean doInBackground(Void... voids) {
// Step 1: Copy asset to filesDir
if (!copyAssetToFile(assetPath, extractedFilePath)) {
errorMessage = "Failed to copy asset file.";
return false;
}
// Step 2: Run tar extraction
String[] cmdline = {"tar", "xf", extractedFilePath, "-C", filesDir};
Process process = null;
try {
process = Runtime.getRuntime().exec(cmdline);
// Capture standard error output (stderr)
BufferedReader errorReader =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
StringBuilder errorOutput = new StringBuilder();
String line;
while ((line = errorReader.readLine()) != null) {
errorOutput.append(line).append("\n");
}
errorReader.close();
// Wait for the process to complete
int exitCode = process.waitFor();
// If there was any output in stderr, treat it as an error
if (exitCode != 0 || errorOutput.length() > 0) {
errorMessage =
errorOutput.toString().isEmpty()
? "Unknown error"
: errorOutput.toString();
return false;
}
return true;
} catch (IOException | InterruptedException e) {
errorMessage = e.getMessage();
return false;
} finally {
if (process != null) {
process.destroy();
}
}
}
@Override
protected void onPostExecute(Boolean success) {
progressDialog.dismiss();
if (success) {
Toast.makeText(
getApplicationContext(),
R.string.extraction_complete,
Toast.LENGTH_SHORT)
.show();
} else {
new AlertDialog.Builder(activity)
.setTitle("Extraction Failed")
.setMessage("Error: " + errorMessage)
.setPositiveButton("OK", null)
.show();
}
}
}.execute();
}
/** Copies the specified asset to the given file path. */
private boolean copyAssetToFile(String assetPath, String outputPath) {
try (InputStream in = getAssets().open(assetPath);
OutputStream out = new FileOutputStream(outputPath)) {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/** Determines the ABI of the device. */
private String getDeviceAbi() {
return Build.SUPPORTED_ABIS[0];
}
@Override
protected void onResume() {
super.onResume();
checkpermissions();
}
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btnInstall) {
File tarGZ = new File(tarPath);
if (tarGZ.exists()) {
tarGZ.delete();
}
alertDialog.show();
} else if (id == R.id.buttonautosetup) {
if (AppConfig.getSetupFiles().contains("arm64-v8a") || AppConfig.getSetupFiles().contains("x86_64")) {
setupVectras64();
} else {
setupVectras32();
}
simpleSetupUIControler(1);
} else if (id == R.id.buttonmanualsetup) {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1001);
} else if (id == R.id.buttonsetuptryagain) {
simpleSetupUIControler(0);
} else if (id == R.id.buttonsetupshowlog) {
linearsimplesetupui.setVisibility(View.GONE);
} else if (id == R.id.textviewshowadvancedsetup) {
linearsimplesetupui.setVisibility(View.GONE);
if (linearstartsetup.getVisibility() == View.VISIBLE) {
alertDialog.show();
}
} else if (id == R.id.buttontryconnectagain) {
linearload.setVisibility(View.VISIBLE);
net.startRequestNetwork(RequestNetworkController.GET,AppConfig.bootstrapfileslink,"anbui",_net_request_listener);
} else if (id == R.id.textviewhideadvancedsetup) {
linearsimplesetupui.setVisibility(View.VISIBLE);
alertDialog.dismiss();
}
}
String tarPath;
// Function to append text and automatically scroll to bottom
@SuppressLint("SetTextI18n")
private void appendTextAndScroll(String textToAdd) {
ScrollView scrollView = findViewById(R.id.scrollView);
// Update the text
vterm.append(textToAdd);
if (textToAdd.contains("xssFjnj58Id")) {
startActivity(new Intent(this, SplashActivity.class));
finish();
} else if (textToAdd.contains("libproot.so --help")){
libprooterror = true;
}
if (textToAdd.contains("Starting setup...")) {
title.setText("Getting ready for you...");
textviewsettingup.setText(R.string.getting_ready_for_you_please_don_t_disconnect_the_network);
} else if (textToAdd.contains("fetch http")) {
title.setText(getString(R.string.connecting_to_mirror_in) + "\n" + selectedMirrorLocation + "...");
textviewsettingup.setText(getString(R.string.connecting_to_mirror_in) + "\n" + selectedMirrorLocation + "...");
} else if (textToAdd.contains("Installing packages...")) {
title.setText(R.string.it_won_t_take_long);
textviewsettingup.setText(R.string.completed_10_it_won_t_take_long);
} else if (textToAdd.contains("(50/")) {
textviewsettingup.setText(R.string.completed_20_it_won_t_take_long);
} else if (textToAdd.contains("100/")) {
textviewsettingup.setText(R.string.completed_30_it_won_t_take_long);
} else if (textToAdd.contains("150/")) {
textviewsettingup.setText(R.string.completed_40_it_won_t_take_long);
} else if (textToAdd.contains("200/")) {
textviewsettingup.setText(R.string.completed_50_it_won_t_take_long);
} else if (textToAdd.contains("Downloading Qemu...")) {
title.setText(R.string.don_t_disconnect);
textviewsettingup.setText(R.string.completed_75_don_t_disconnect);
} else if (textToAdd.contains("Installing Qemu...")) {
title.setText(R.string.keep_it_up);
textviewsettingup.setText(R.string.completed_80_keep_it_up);
} else if (textToAdd.contains("qemu-system")) {
textviewsettingup.setText(R.string.completed_95_keep_it_up);
} else if (textToAdd.contains("Just a sec...")) {
title.setText(R.string.almost_there);
textviewsettingup.setText(getString(R.string.almost_there));
}
// Scroll to the bottom
scrollView.post(new Runnable() {
@Override
public void run() {
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
public void onBackPressed() {
super.onBackPressed();
return;
}
// Method to execute the shell command
public void executeShellCommand(String userCommand) {
new Thread(() -> {
try {
// Setup the process builder to start PRoot with environmental variables and commands
ProcessBuilder processBuilder = new ProcessBuilder();
// Adjust these environment variables as necessary for your app
String filesDir = activity.getFilesDir().getAbsolutePath();
String nativeLibDir = activity.getApplicationInfo().nativeLibraryDir;
File tmpDir = new File(activity.getFilesDir(), "usr/tmp");
// Setup environment for the PRoot process
processBuilder.environment().put("PROOT_TMP_DIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("HOME", "/root");
processBuilder.environment().put("USER", "root");
processBuilder.environment().put("PATH", "/bin:/usr/bin:/sbin:/usr/sbin");
processBuilder.environment().put("TERM", "xterm-256color");
processBuilder.environment().put("TMPDIR", tmpDir.getAbsolutePath());
processBuilder.environment().put("SHELL", "/bin/sh");
String[] prootCommand = {
TermuxService.PREFIX_PATH + "/bin/proot", // PRoot binary path
"--kill-on-exit",
"--link2symlink",
"-0",
"-r", filesDir + "/distro", // Path to the rootfs
"-b", "/dev",
"-b", "/proc",
"-b", "/sys",
"-b", "/sdcard",
"-b", "/storage",
"-b", "/data",
"-w", "/root",
"/bin/sh",
"--login"// The shell to execute inside PRoot
};
processBuilder.command(prootCommand);
Process process = processBuilder.start();
// Get the input and output streams of the process
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
// Send user command to PRoot
writer.write(userCommand);
writer.newLine();
writer.flush();
writer.close();
// Read the input stream for the output of the command
String line;
while ((line = reader.readLine()) != null) {
final String outputLine = line;
activity.runOnUiThread(() -> appendTextAndScroll(outputLine + "\n"));
}
// Read any errors from the error stream
while ((line = errorReader.readLine()) != null) {
final String errorLine = line;
activity.runOnUiThread(() -> appendTextAndScroll(errorLine + "\n"));
}
// Clean up
reader.close();
errorReader.close();
// Wait for the process to finish
process.waitFor();
// Wait for the process to finish
int exitValue = process.waitFor();
// Check if the exit value indicates an error
if (exitValue != 0) {
// If exit value is not zero, display a toast message
String toastMessage = "Command failed with exit code: " + exitValue;
activity.runOnUiThread(() -> {
appendTextAndScroll("Error: " + toastMessage + "\n");
Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show();
inBtn.setVisibility(View.VISIBLE);
title.setText("Failed!");
simpleSetupUIControler(2);
});
if (libprooterror) {
AlertDialog alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create();
alertDialog.setTitle(getResources().getString(R.string.oops));
alertDialog.setMessage(getResources().getString(R.string.a_serious_problem_has_occurred));
alertDialog.setCancelable(false);
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.join_our_community), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(ACTION_VIEW);
intent.setData(Uri.parse(AppConfig.community));
startActivity(intent);
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(R.string.close), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertDialog.show();
}
}
} catch (IOException | InterruptedException e) {
// Handle exceptions by printing the stack trace in the terminal output
final String errorMessage = e.getMessage();
activity.runOnUiThread(() -> {
appendTextAndScroll("Error: " + errorMessage + "\n");
Toast.makeText(activity, "Error executing command: " + errorMessage, Toast.LENGTH_LONG).show();
inBtn.setVisibility(View.VISIBLE);
title.setText("Failed!");
simpleSetupUIControler(2);
});
}
}).start(); // Execute the command in a separate thread to prevent blocking the UI thread
}
private void startDownload() {
new DownloadFileTask(activity).execute(AppConfig.getSetupFiles());
}
private class DownloadFileTask extends AsyncTask<String, Integer, String> {
private Context context;
private ProgressDialog progressDialog;
private int fileLength;
public DownloadFileTask(Context context) {
this.context = context;
}
@Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context, R.style.MainDialogTheme);
progressDialog.setTitle("Downloading... Please do not disconnect from the network.");
progressDialog.setMessage(null);
progressDialog.setIndeterminate(true);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false); // Allow canceling with back button
progressDialog.show();
}
@Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
fileLength = connection.getContentLength();
input = connection.getInputStream();
output = new FileOutputStream(tarPath);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
if (isCancelled()) {
input.close();
return null;
}
total += count;
if (fileLength > 0) {
publishProgress((int) (total * 100 / fileLength));
}
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// If you get here, the length of the file is known.
progressDialog.setIndeterminate(false);
progressDialog.setMax(100);
progressDialog.setProgress(progress[0]);
// Convert the bytes downloaded to MB and update the dialog message accordingly.
int progressMB = (int) ((progress[0] / 100.0) * fileLength / (1024 * 1024));
progressDialog.setMessage(progressMB + " MB/" + fileLength / (1024 * 1024) + " MB");
}
@Override
protected void onPostExecute(String result) {
progressDialog.dismiss(); // Dismiss the progress dialog
if (result != null) {
Toast.makeText(context, "Download error: " + result, Toast.LENGTH_LONG).show();
inBtn.setVisibility(View.VISIBLE);
title.setText("Failed!");
} else
setupVectras();
}
}
private void setupVectras() {
simpleSetupUIControler(1);
inBtn.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
String filesDir = activity.getFilesDir().getAbsolutePath();
String cmd = "";
cmd += selectedMirrorCommand + ";";
executeShellCommand(cmd);
executeShellCommand("set -e;" +
" echo \"Starting setup...\";" +
" apk update;" +
" echo \"Installing packages...\";" +
" apk add " + AppConfig.neededPkgs + ";" +
" echo \"Installing Qemu...\";" +
" tar -xzvf " + tarPath + " -C /;" +
" rm " + tarPath + ";" +
" echo \"Just a sec...\";" +
" apk add qemu-audio-sdl pulseaudio;" +
" echo export PULSE_SERVER=127.0.0.1 >> /etc/profile;" +
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;" +
" echo \"installation successful! xssFjnj58Id\"");
}
private void setupVectras32() {
inBtn.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
String filesDir = activity.getFilesDir().getAbsolutePath();
String cmd = "";
cmd += selectedMirrorCommand + ";";
executeShellCommand(cmd);
executeShellCommand("set -e;" +
" echo \"Starting setup...\";" +
" apk update;" +
" echo \"Installing packages...\";" +
" apk add " + AppConfig.neededPkgs + ";" +
//" tar -xzvf " + tarPath + " -C /;" +
" echo \"Installing Qemu...\";" +
" apk add qemu-system-x86_64 qemu-system-ppc qemu-system-i386 qemu-system-aarch64 qemu-pr-helper qemu-img qemu-audio-sdl pulseaudio mesa-dri-gallium;" +
" echo \"Just a sec...\";" +
" echo export PULSE_SERVER=127.0.0.1 >> /etc/profile;" +
//" rm " + tarPath + ";" +
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;" +
" echo \"installation successful! xssFjnj58Id\"");
}
private void setupVectras64() {
inBtn.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
String filesDir = activity.getFilesDir().getAbsolutePath();
String cmd = "";
cmd += selectedMirrorCommand + ";";
executeShellCommand(cmd);
executeShellCommand("set -e;" +
" echo \"Starting setup...\";" +
" apk update;" +
" echo \"Installing packages...\";" +
" apk add " + AppConfig.neededPkgs + ";" +
" echo \"Downloading Qemu...\";" +
" curl -o setup.tar.gz -L " + bootstrapfilelink + ";" +
" echo \"Installing Qemu...\";" +
" tar -xzvf setup.tar.gz -C /;" +
" rm setup.tar.gz;" +
" echo \"Just a sec...\";" +
" apk add qemu-audio-sdl pulseaudio;" +
" echo export PULSE_SERVER=127.0.0.1 >> /etc/profile;" +
" mkdir -p ~/.vnc && echo -e \"555555\\n555555\" | vncpasswd -f > ~/.vnc/passwd && chmod 0600 ~/.vnc/passwd;" +
" echo \"installation successful! xssFjnj58Id\"");
}
private void checkabi() {
if (!AppConfig.getSetupFiles().contains("arm64-v8a")) {
if (!AppConfig.getSetupFiles().contains("x86_64")) {
VectrasApp.oneDialog(getResources().getString(R.string.warning), getResources().getString(R.string.cpu_not_support_64), true, false, activity);
}
}
alertDialog = new AlertDialog.Builder(activity, R.style.MainDialogTheme).create();
alertDialog.setTitle(getString(R.string.bootstrap_required));
alertDialog.setMessage(getString(R.string.you_can_choose_between_auto_download_and_setup_or_manual_setup_by_choosing_bootstrap_file));
alertDialog.setCancelable(false);
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.auto_setup), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//startDownload();
if (AppConfig.getSetupFiles().contains("arm64-v8a") || AppConfig.getSetupFiles().contains("x86_64")) {
setupVectras64();
} else {
setupVectras32();
}
simpleSetupUIControler(1);
return;
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.manual_setup), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.DIRECTORY_DOWNLOADS);
}
startActivityForResult(intent, 1001);
}
});
}
private void checkpermissions() {
if (VectrasApp.checkpermissionsgranted(activity, true)) {
if (!settingup) {
settingup = true;
checkabi();
File tarGZ = new File(tarPath);
if (tarGZ.exists()) {
setupVectras();
} else {
if (linearsimplesetupui.getVisibility() == View.GONE) {
alertDialog.show();
}
}
}
}
}
private void simpleSetupUIControler(int status) {
if (status == 0) {
linearstartsetup.setVisibility(View.VISIBLE);
linearsettingup.setVisibility(View.GONE);
linearsetupfailed.setVisibility(View.GONE);
} else if (status == 1) {
linearstartsetup.setVisibility(View.GONE);
linearsettingup.setVisibility(View.VISIBLE);
linearsetupfailed.setVisibility(View.GONE);
} else if (status == 2) {
linearstartsetup.setVisibility(View.GONE);
linearsettingup.setVisibility(View.GONE);
linearsetupfailed.setVisibility(View.VISIBLE);
}
}
public String getPath(Uri uri) {
return com.vectras.vm.utils.FileUtils.getPath(this, uri);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent ReturnedIntent) {
super.onActivityResult(requestCode, resultCode, ReturnedIntent);
if (requestCode == 1001 && resultCode == RESULT_OK) {
Uri content_describer = ReturnedIntent.getData();
File selectedFilePath = new File(getPath(content_describer));
ProgressBar loading = progressBar;
String abi = Build.SUPPORTED_ABIS[0];
if (selectedFilePath.toString().endsWith(abi+".tar.gz")) {
loading.setVisibility(View.VISIBLE);
new Thread(new Runnable() {
@Override
public void run() {
FileInputStream File = null;
try {
File = (FileInputStream) getContentResolver().openInputStream(content_describer);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
try {
try {
OutputStream out = new FileOutputStream(new File(tarPath));
try {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = File.read(buf)) > 0) {
out.write(buf, 0, len);
}
} finally {
out.close();
}
} finally {
Runnable runnable = new Runnable() {
@Override
public void run() {
loading.setVisibility(View.GONE);
alertDialog.dismiss();
setupVectras();
MainSettingsManager.setsetUpWithManualSetupBefore(SetupQemuActivity.this, true);
}
};
activity.runOnUiThread(runnable);
File.close();
}
} catch (IOException e) {
Runnable runnable = new Runnable() {
@Override
public void run() {
loading.setVisibility(View.GONE);
UIAlert(activity, e.toString(), "error");
}
};
activity.runOnUiThread(runnable);
}
}
}).start();
} else {
if (linearsimplesetupui.getVisibility() == View.GONE) {
alertDialog.show();
}
UIAlert(activity, "INVALID FILE", "please select vectras-vm-" + abi + ".tar.gz file");
}
} else
if (linearsimplesetupui.getVisibility() == View.GONE) {
alertDialog.show();
}
}
private void setupSpiner() {
VectrasApp.setupMirrorListForListmap(listmapForSelectMirrors);
spinnerselectmirror.setAdapter(new SpinnerSelectMirrorAdapter(listmapForSelectMirrors));
spinnerselectmirror.setSelection(MainSettingsManager.getSelectedMirror(activity));
}
public class SpinnerSelectMirrorAdapter extends BaseAdapter {
ArrayList<HashMap<String, String>> _data;
public SpinnerSelectMirrorAdapter(ArrayList<HashMap<String, String>> _arr) {
_data = _arr;
}
@Override
public int getCount() {
return _data.size();
}
@Override
public HashMap<String, String> getItem(int _index) {
return _data.get(_index);
}
@Override
public long getItemId(int _index) {
return _index;
}
@Override
public View getView(final int _position, View _v, ViewGroup _container) {
LayoutInflater _inflater = getLayoutInflater();
View _view = _v;
if (_view == null) {
_view = _inflater.inflate(R.layout.simple_layout_for_spiner, null);
}
final TextView textViewLocation = _view.findViewById(R.id.textViewLocation);
textViewLocation.setText(Objects.requireNonNull(_data.get((int) _position).get("location")));
return _view;
}
}
}