Format code in DownloadActivity

This commit is contained in:
Akash Yadav
2022-01-10 13:14:15 +05:30
parent 22071e6aee
commit 003a7bd229
3 changed files with 213 additions and 224 deletions
@@ -1,35 +1,34 @@
/************************************************************************************
/*
* This file is part of AndroidIDE.
*
*
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*
**************************************************************************************/
*/
package com.itsaky.androidide;
import abhishekti7.unicorn.filepicker.UnicornFilePicker;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import androidx.core.content.ContextCompat;
import androidx.transition.TransitionManager;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.blankj.utilcode.util.ThreadUtils;
@@ -49,175 +48,173 @@ import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.FileUtil;
import com.itsaky.androidide.utils.InputStreamLineReader;
import com.itsaky.toaster.Toaster;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
public class DownloadActivity extends StudioActivity {
private ActivityDownloadBinding binding;
private ProgressSheet progressSheet;
private File choosenDir = null;
@Override
protected View bindLayout() {
binding = ActivityDownloadBinding.inflate(getLayoutInflater());
return binding.getRoot();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnClickListener clickListener = v -> handleClick(v);
binding.dismiss.setOnClickListener(clickListener);
binding.choose.setOnClickListener(clickListener);
binding.install.setOnClickListener(clickListener);
binding.install.setEnabled(false);
}
private void handleClick(View v) {
final int id = v.getId();
if(id == binding.dismiss.getId()) {
TransitionManager.beginDelayedTransition(binding.getRoot());
binding.card.setVisibility(View.GONE);
} else if(id == binding.choose.getId()) {
try {
binding.install.setEnabled(false);
UnicornFilePicker.from(this)
.addConfigBuilder()
.addItemDivider(false)
.selectMultipleFiles(false)
.setRootDirectory(FileUtil.getExternalStorageDir())
.showHiddenFiles(true)
.showOnlyDirectory(true)
.theme(R.style.AppTheme_FilePicker)
.build()
.forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE);
} catch (Throwable th){
LOG.error(getString (R.string.err_cannot_start_file_picker), th);
}
} else if(id == binding.install.getId()) {
if(choosenDir == null) {
getApp().toast(R.string.msg_pick_files, Toaster.Type.ERROR);
return;
}
if(!choosenDir.exists()) {
getApp().toast(R.string.msg_file_doesnt_exist, Toaster.Type.ERROR);
return;
}
installAll();
}
}
private final String DONE = "DONE";
private void installAll() {
showProgress();
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_DOWNLOADED, true);
try {
final File script = createExtractScript();
final ProcessStreamsHolder holder = new ProcessStreamsHolder ();
final IProcessExecutor executor = ProcessExecutorFactory.commonExecutor();
private ActivityDownloadBinding binding;
private ProgressSheet progressSheet;
private File choosenDir = null;
@Override
protected View bindLayout () {
binding = ActivityDownloadBinding.inflate (getLayoutInflater ());
return binding.getRoot ();
}
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
final OnClickListener clickListener = this::handleClick;
binding.dismiss.setOnClickListener (clickListener);
binding.choose.setOnClickListener (clickListener);
binding.install.setOnClickListener (clickListener);
binding.install.setEnabled (false);
}
private void handleClick (View v) {
final int id = v.getId ();
if (id == binding.dismiss.getId ()) {
TransitionManager.beginDelayedTransition (binding.getRoot ());
binding.card.setVisibility (View.GONE);
} else if (id == binding.choose.getId ()) {
try {
binding.install.setEnabled (false);
UnicornFilePicker.from (this)
.addConfigBuilder ()
.addItemDivider (false)
.selectMultipleFiles (false)
.setRootDirectory (FileUtil.getExternalStorageDir ())
.showHiddenFiles (true)
.showOnlyDirectory (true)
.theme (R.style.AppTheme_FilePicker)
.build ()
.forResult (abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE);
} catch (Throwable th) {
LOG.error (getString (R.string.err_cannot_start_file_picker), th);
}
} else if (id == binding.install.getId ()) {
if (choosenDir == null) {
getApp ().toast (R.string.msg_pick_files, Toaster.Type.ERROR);
return;
}
executor.execAsync(holder,
code -> onInstallProcessExit (code),
true,
Environment.BUSYBOX.getAbsolutePath(), "sh",// We use busybox's sh, because Environment.SHELL is not installed yet...
script.getAbsolutePath()
if (!choosenDir.exists ()) {
getApp ().toast (R.string.msg_file_doesnt_exist, Toaster.Type.ERROR);
return;
}
installAll ();
}
}
private void installAll () {
showProgress ();
getApp ().getPrefManager ().putBoolean (PreferenceManager.KEY_FRAMEWORK_DOWNLOADED, true);
try {
final File script = createExtractScript ();
final ProcessStreamsHolder holder = new ProcessStreamsHolder ();
final IProcessExecutor executor = ProcessExecutorFactory.commonExecutor ();
executor.execAsync (holder,
this::onInstallProcessExit,
true,
Environment.BUSYBOX.getAbsolutePath (), "sh",// We use busybox's sh, because Environment.SHELL is not installed yet...
script.getAbsolutePath ()
);
final InputStreamLineReader reader = new InputStreamLineReader (holder.in, line -> onInstallationOutput (line));
new Thread (reader).start();
final InputStreamLineReader reader = new InputStreamLineReader (holder.in, this::onInstallationOutput);
new Thread (reader).start ();
} catch (DownloadActivity.InstallationException e) {
LOG.error(getString(R.string.err_installation), e);
onInstallationFailed(e.exitCode);
LOG.error (getString (R.string.err_installation), e);
onInstallationFailed (e.exitCode);
} catch (IOException e) {
LOG.error(getString(R.string.err_installation), e);
onInstallationFailed(5); // Exit code 5 : I/O Error
LOG.error (getString (R.string.err_installation), e);
onInstallationFailed (5); // Exit code 5 : I/O Error
}
}
}
private void onInstallationOutput (final String line) {
ThreadUtils.runOnUiThread(() -> {
getProgressSheet().setSubMessage(line);
});
ThreadUtils.runOnUiThread (() -> getProgressSheet ().setSubMessage (line));
}
private void onInstallProcessExit (final int code) {
ThreadUtils.runOnUiThread(() -> {
ThreadUtils.runOnUiThread (() -> {
if (code == 0) { // 0 = normal execution
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_INSTALLED, true);
showRestartNeeded();
if(getProgressSheet().isShowing()) {
getProgressSheet().dismiss();
getApp ().getPrefManager ().putBoolean (PreferenceManager.KEY_FRAMEWORK_INSTALLED, true);
showRestartNeeded ();
if (getProgressSheet ().isShowing ()) {
getProgressSheet ().dismiss ();
}
} else {
onInstallationFailed (code);
}
});
}
private void onInstallationFailed(int code) {
private void onInstallationFailed (int code) {
// TODO Can this be improved by adding some animations?
if(getProgressSheet().isShowing()) {
getProgressSheet().dismiss();
if (getProgressSheet ().isShowing ()) {
getProgressSheet ().dismiss ();
}
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (this);
builder.setTitle(R.string.title_installation_failed);
builder.setMessage(getString(R.string.msg_installation_failed, code));
builder.setPositiveButton(android.R.string.ok, (d, w) -> {
d.dismiss();
finishAffinity();
builder.setTitle (R.string.title_installation_failed);
builder.setMessage (getString (R.string.msg_installation_failed, code));
builder.setPositiveButton (android.R.string.ok, (d, w) -> {
d.dismiss ();
finishAffinity ();
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
builder.setNegativeButton (android.R.string.cancel, null);
builder.show ();
}
private File createExtractScript() throws DownloadActivity.InstallationException {
private File createExtractScript () throws DownloadActivity.InstallationException {
final StringBuilder sb = new StringBuilder ();
sb.append("cd");
joiner(sb);
sb.append("echo 'Installing...'");
joiner(sb);
sb.append ("cd");
joiner (sb);
sb.append ("echo 'Installing...'");
joiner (sb);
File[] files = choosenDir.listFiles(ARCHIVE_FILTER);
File[] files = choosenDir.listFiles (ARCHIVE_FILTER);
if (files == null || files.length <= 0) {
throw new InstallationException (2);
}
for (File f : files) {
if(f.getName().endsWith(".tar.xz")) {
if(f.getName().startsWith("androidide-sysroot")) {
sb.append("cd $SYSROOT/..");
joiner(sb);
if (f.getName ().endsWith (".tar.xz")) {
if (f.getName ().startsWith ("androidide-sysroot")) {
sb.append ("cd $SYSROOT/..");
joiner (sb);
}
sb.append("$BUSYBOX tar xvJf '" + f.getAbsolutePath() + "'");
joiner(sb);
sb.append("cd $HOME");
joiner(sb);
} else if(f.getName().endsWith(".zip")) {
sb.append("$BUSYBOX unzip '" + f.getAbsolutePath() + "'");
joiner(sb);
sb.append ("$BUSYBOX tar xvJf '").append (f.getAbsolutePath ()).append ("'");
joiner (sb);
sb.append ("cd $HOME");
joiner (sb);
} else if (f.getName ().endsWith (".zip")) {
sb.append ("$BUSYBOX unzip '").append (f.getAbsolutePath ()).append ("'");
joiner (sb);
}
}
sb.append("echo 'Cleaning unsupported flags in binaries...'");
joiner(sb);
sb.append("$BUSYBOX find $JAVA_HOME -type f -exec androidide-cleaner {} \\;");
joiner(sb);
sb.append("echo " + DONE);
sb.append ("echo 'Cleaning unsupported flags in binaries...'");
joiner (sb);
sb.append ("$BUSYBOX find $JAVA_HOME -type f -exec androidide-cleaner {} \\;");
joiner (sb);
String DONE = "DONE";
sb.append ("echo ").append (DONE);
final File script = new File (Environment.TMP_DIR, "extract_tools.sh");
if (!FileIOUtils.writeFileFromString(script, sb.toString())) {
if (!FileIOUtils.writeFileFromString (script, sb.toString ())) {
throw new InstallationException (2);
}
@@ -225,85 +222,77 @@ public class DownloadActivity extends StudioActivity {
}
private void joiner (StringBuilder sb) {
sb.append(" && ");
sb.append (" && ");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE && resultCode == RESULT_OK) {
ArrayList<String> files = data.getStringArrayListExtra("filePaths");
if(files != null) {
if(files.size() == 1) {
File choosenDir = new File(files.get(0));
if(choosenDir.exists() && choosenDir.isDirectory()) {
this.choosenDir = choosenDir;
setDone(binding.choose);
binding.install.setEnabled(true);
new TaskExecutor().executeAsync(new ListDirectoryCallable(choosenDir), __ -> {
binding.filesText.setText(getString(R.string.msg_installable_files, __));
});
} else {
getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR);
choosenDir = null;
}
} else {
getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR);
}
}
}
}
private void setDone(MaterialButton button) {
final int dp8 = SizeUtils.dp2px(8);
final int dp4 = SizeUtils.dp2px(4);
final int dp24 = SizeUtils.dp2px(24);
button.setText("");
button.setIconResource(R.drawable.ic_ok);
button.setIconTint(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.bg_green)));
button.setBackgroundColor(android.graphics.Color.TRANSPARENT);
button.setPaddingRelative(dp8, dp4, dp8, dp4);
button.setStrokeWidth(0);
button.setGravity(Gravity.CENTER);
button.setIconPadding(0);
button.setInsetTop(0);
button.setInsetBottom(0);
button.setPaddingRelative(dp24, dp4, dp24, dp4);
}
private void showProgress() {
getProgressSheet().setCancelable(false);
getProgressSheet().setShowShadow(false);
getProgressSheet().setSubMessageEnabled(true)
.setWelcomeTextEnabled(true)
.show(getSupportFragmentManager(), "progress_sheet");
}
private void showRestartNeeded() {
setDone(binding.install);
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (this);
builder.setTitle(R.string.title_restart);
builder.setMessage(R.string.msg_restart);
builder.setCancelable(false);
builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity());
builder.create().show();
}
private ProgressSheet getProgressSheet() {
return progressSheet == null ? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait)) : progressSheet;
}
private final FileFilter ARCHIVE_FILTER = new FileFilter(){
@Override
public boolean accept(File p1) {
return p1.isFile() && (p1.getName().endsWith(".tar.xz") || p1.getName().endsWith(".zip"));
}
};
private class InstallationException extends Exception {
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
super.onActivityResult (requestCode, resultCode, data);
if (requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE && resultCode == RESULT_OK) {
ArrayList<String> files = data.getStringArrayListExtra ("filePaths");
if (files != null) {
if (files.size () == 1) {
File choosenDir = new File (files.get (0));
if (choosenDir.exists () && choosenDir.isDirectory ()) {
this.choosenDir = choosenDir;
setDone (binding.choose);
binding.install.setEnabled (true);
new TaskExecutor ().executeAsync (new ListDirectoryCallable (choosenDir), __ -> binding.filesText.setText (getString (R.string.msg_installable_files, __)));
} else {
getApp ().toast (R.string.msg_picked_isnt_dir, Toaster.Type.ERROR);
}
} else {
getApp ().toast (R.string.msg_pick_single_file, Toaster.Type.ERROR);
}
}
}
}
private void setDone (MaterialButton button) {
final int dp8 = SizeUtils.dp2px (8);
final int dp4 = SizeUtils.dp2px (4);
final int dp24 = SizeUtils.dp2px (24);
button.setText ("");
button.setIconResource (R.drawable.ic_ok);
button.setIconTint (ColorStateList.valueOf (ContextCompat.getColor (this, R.color.bg_green)));
button.setBackgroundColor (android.graphics.Color.TRANSPARENT);
button.setPaddingRelative (dp8, dp4, dp8, dp4);
button.setStrokeWidth (0);
button.setGravity (Gravity.CENTER);
button.setIconPadding (0);
button.setInsetTop (0);
button.setInsetBottom (0);
button.setPaddingRelative (dp24, dp4, dp24, dp4);
}
private void showProgress () {
getProgressSheet ().setCancelable (false);
getProgressSheet ().setShowShadow (false);
getProgressSheet ().setSubMessageEnabled (true)
.setWelcomeTextEnabled (true)
.show (getSupportFragmentManager (), "progress_sheet");
}
private void showRestartNeeded () {
setDone (binding.install);
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder (this);
builder.setTitle (R.string.title_restart);
builder.setMessage (R.string.msg_restart);
builder.setCancelable (false);
builder.setPositiveButton (android.R.string.ok, (p1, p2) -> finishAffinity ());
builder.create ().show ();
}
private ProgressSheet getProgressSheet () {
return progressSheet == null ? progressSheet = new ProgressSheet ().setMessage (getString (R.string.please_wait)) : progressSheet;
}
private final FileFilter ARCHIVE_FILTER = p1 -> p1.isFile () && (p1.getName ().endsWith (".tar.xz") || p1.getName ().endsWith (".zip"));
private static class InstallationException extends Exception {
private final int exitCode;
public InstallationException(int exitCode) {
public InstallationException (int exitCode) {
this.exitCode = exitCode;
}
}
@@ -353,7 +353,7 @@ public class IDEService {
final ProcessStreamsHolder holder = new ProcessStreamsHolder();
listener.saveFiles();
Environment.mkdirIfNotExits(Environment.TMP_DIR);
currentTask = task;
listener.appendOutput(task, getString(R.string.msg_task_begin, currentTime(), task.getName()));
try {
@@ -69,32 +69,32 @@ public class BootstrapInstaller {
LOG.error ("Cannot delete staging directory");
throw new CompletionException (new InstallationException (context.getString (R.string.msg_delete_sysroot_staging)));
}
if (SYSROOT.exists () && !FileUtils.delete (SYSROOT)) {
LOG.error ("Cannot delete sysroot directory.");
throw new CompletionException (new InstallationException (context.getString (R.string.msg_delete_sysroot)));
}
if (stagingDir.exists () && !FileUtils.createOrExistsDir (stagingDir)) {
LOG.error ("Cannot create staging directory");
throw new CompletionException (new InstallationException (context.getString (R.string.msg_create_sysroot_staging)));
}
if (SYSROOT.exists () && !FileUtils.createOrExistsDir (SYSROOT)) {
LOG.error ("Cannot create sysroot directory");
throw new CompletionException (new InstallationException (context.getString (R.string.msg_create_sysroot)));
}
final var buffer = new byte[8096];
final var symlinks = new ArrayList<Pair<String, String>> (50);
ZipEntry entry;
while ((entry = zip.getNextEntry ()) != null) {
msg = "Reading zip entry " + entry.getName ();
notify (listener, msg);
LOG.verbose (msg);
if (entry.getName ().equals ("SYMLINKS.txt")) {
msg = "Reading SYMLINKS.txt...";
notify (listener, msg);
LOG.debug (msg);
@@ -127,39 +127,39 @@ public class BootstrapInstaller {
LOG.error ("Cannot create target file parent directory");
throw new CompletionException (new InstallationException (context.getString (R.string.msg_mkdir_failed, ___.getAbsolutePath ())));
}
if (!isDirectory) {
try (final var outStream = new FileOutputStream (targetFile)) {
int readBytes;
while ((readBytes = zip.read (buffer)) != -1)
outStream.write (buffer, 0, readBytes);
}
if (zipEntryName.startsWith ("bin/") || zipEntryName.startsWith ("libexec") ||
zipEntryName.startsWith ("lib/apt/apt-helper") || zipEntryName.startsWith ("lib/apt/methods")) {
notify (listener, context.getString(R.string.msg_chmod_exec));
notify (listener, context.getString (R.string.msg_chmod_exec));
LOG.verbose ("chmod 0700", zipEntryName);
//noinspection OctalInteger
Os.chmod (targetFile.getAbsolutePath (), 0700);
}
}
}
}
if (symlinks.isEmpty()) {
if (symlinks.isEmpty ()) {
LOG.error ("No SYMLINKS.txt file encountered...");
throw new CompletionException (new InstallationException ("No SYMLINKS.txt encountered"));
}
for (Pair<String, String> symlink : symlinks) {
notify (listener, context.getString (R.string.msg_linking, symlink.second, symlink.first));
Os.symlink(symlink.first, symlink.second);
Os.symlink (symlink.first, symlink.second);
}
LOG.info ("Renaming 'sysroot-staging' directory to 'sysroot'");
if (!FileUtils.rename (stagingDir, SYSROOT.getName ())) {
LOG.error ("Cannot rename 'sysroot-staging' to 'sysroot'");
throw new CompletionException (new InstallationException ("Failed to rename staging sysroot directory."));
@@ -167,9 +167,9 @@ public class BootstrapInstaller {
notify (listener, context.getString (R.string.msg_extracting_hooks));
ToolsManager.extractLibHooks ();
LOG.info ("Bootstrap packages installed successfully.");
} catch (IOException| ErrnoException e) {
} catch (IOException | ErrnoException e) {
LOG.error ("Failed to extract bootstrap", e);
throw new RuntimeException (e);
}