mirror of
https://github.com/xoureldeen/Vectras-VM-Android.git
synced 2026-04-29 14:59:50 +00:00
912 lines
39 KiB
Java
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;
|
|
}
|
|
}
|
|
}
|