diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..35f63c6 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdk 32 + + defaultConfig { + applicationId "com.xypower.frpandroid" + minSdk 25 + targetSdk 32 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + buildConfigField("String", "FrpVersion", '"0.56.0"') + buildConfigField("String", "FrpcFileName", '"libfrpc.so"') + buildConfigField("String", "LogFileName", '"frpc.log"') + buildConfigField("String", "ConfigFileName", '"config.toml"') + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + } + } + + packagingOptions { + jniLibs { + useLegacyPackaging true + } + } + splits { + abi { + enable true + reset() + include "arm64-v8a", "x86_64", "armeabi-v7a" + universalApk true + } + } +} + +dependencies { + + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:2.0.4' + implementation 'org.jetbrains:annotations:15.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} \ No newline at end of file diff --git a/app/libs/arm64-v8a/libfrpc.so b/app/libs/arm64-v8a/libfrpc.so new file mode 100644 index 0000000..47ab8bc Binary files /dev/null and b/app/libs/arm64-v8a/libfrpc.so differ diff --git a/app/libs/armeabi-v7a/libfrpc.so b/app/libs/armeabi-v7a/libfrpc.so new file mode 100644 index 0000000..584ee53 Binary files /dev/null and b/app/libs/armeabi-v7a/libfrpc.so differ diff --git a/app/libs/x86_64/libfrpc.so b/app/libs/x86_64/libfrpc.so new file mode 100644 index 0000000..0653da4 Binary files /dev/null and b/app/libs/x86_64/libfrpc.so differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..08e57a4 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/config.toml b/app/src/main/assets/config.toml new file mode 100644 index 0000000..488975e --- /dev/null +++ b/app/src/main/assets/config.toml @@ -0,0 +1,20 @@ +serverAddr = "61.169.135.146" +serverPort = 7000 +dnsServer = "114.114.114.114" +auth.method = "token" +auth.token = "mint" +transport.tls.enable=false +transport.tls.disableCustomTLSFirstByte = false + + + +[log] +level = "debug" +disablePrintColor = true + +[[proxies]] +name = "p2p_adb" +type = "xtcp" +secretKey = "123456" +localIP = "127.0.0.1" +localPort = 5555 \ No newline at end of file diff --git a/app/src/main/java/com/xypower/frpandroid/ConfigActivity.java b/app/src/main/java/com/xypower/frpandroid/ConfigActivity.java new file mode 100644 index 0000000..0ee1848 --- /dev/null +++ b/app/src/main/java/com/xypower/frpandroid/ConfigActivity.java @@ -0,0 +1,125 @@ +package com.xypower.frpandroid; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; + +import org.jetbrains.annotations.Nullable; + +import java.io.BufferedReader; +import java.io.Closeable; +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.Reader; +import java.nio.charset.Charset; + +public class ConfigActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_config); + + Button saveConfigButton = (Button)this.findViewById(R.id.saveConfigButton); + saveConfigButton.setOnClickListener((View.OnClickListener)(new View.OnClickListener() { + public final void onClick(View it) { + ConfigActivity.this.saveConfig(); + ConfigActivity.this.finish(); + } + })); + Button dontSaveConfigButton = (Button)this.findViewById(R.id.dontSaveConfigButton); + dontSaveConfigButton.setOnClickListener((View.OnClickListener)(new View.OnClickListener() { + public final void onClick(View it) { + ConfigActivity.this.finish(); + } + })); + this.readConfig(); + } + + public final void readConfig() { + String[] files = this.fileList(); + if (files == null) { + return; + } + + EditText configEditText = (EditText)this.findViewById(R.id.configEditText); + configEditText.setText((CharSequence)""); + + FileInputStream fileInputStream = null; + try { + fileInputStream = openFileInput("config.toml"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + if (fileInputStream != null) { + InputStream var4 = (InputStream)fileInputStream; + // Charset var5 = Charsets.UTF_8; + Reader reader = (Reader)(new InputStreamReader(var4, Charset.defaultCharset())); + short var7 = 8192; + BufferedReader mReader = reader instanceof BufferedReader ? (BufferedReader)reader : new BufferedReader(reader, var7); + StringBuffer mRespBuff = new StringBuffer(); + char[] buff = new char[1024]; + boolean var13 = false; + + while(true) { + int var14 = 0; + try { + var14 = mReader.read(buff); + } catch (IOException e) { + e.printStackTrace(); + } + if (var14 == -1) { + try { + mReader.close(); + } catch (IOException e) { + } + configEditText.setText((CharSequence)mRespBuff.toString()); + break; + } + + mRespBuff.append(buff, 0, var14); + } + } + } + + private static final void closeFinally(Closeable closable) { + if (closable != null) { + try { + closable.close(); + } catch (Throwable var3) { + // ExceptionsKt.addSuppressed(cause, var3); + } + } + } + + public final void saveConfig() { + EditText configEditText = (EditText)this.findViewById(R.id.configEditText); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = this.openFileOutput("config.toml", 0); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + try { + // Intrinsics.checkNotNullExpressionValue(configEditText, "configEditText"); + String var6 = configEditText.getText().toString(); + byte[] var8 = var6.getBytes(Charset.defaultCharset()); + // Intrinsics.checkNotNullExpressionValue(var8, "this as java.lang.String).getBytes(charset)"); + fileOutputStream.write(var8); + // Unit var13 = Unit.INSTANCE; + } catch (Throwable ex) { + ex.printStackTrace(); + } finally { + closeFinally(fileOutputStream); + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/frpandroid/MainActivity.java b/app/src/main/java/com/xypower/frpandroid/MainActivity.java new file mode 100644 index 0000000..c028e68 --- /dev/null +++ b/app/src/main/java/com/xypower/frpandroid/MainActivity.java @@ -0,0 +1,259 @@ +package com.xypower.frpandroid; + +import android.app.ActivityManager; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.os.IBinder; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.SwitchCompat; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; + +import org.jetbrains.annotations.NotNull; + +import java.io.Closeable; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Iterator; + +public class MainActivity extends AppCompatActivity { + + private Switch state_switch; + private Switch auto_start_switch; + private ShellService mService; + private boolean mBound; + + private final ServiceConnection connection = new ServiceConnection() { + public void onServiceConnected(@NotNull ComponentName className, @NotNull IBinder service) { + // Intrinsics.checkNotNullParameter(className, "className"); + // Intrinsics.checkNotNullParameter(service, "service"); + ShellService.LocalBinder binder = (ShellService.LocalBinder)service; + MainActivity.this.mService = binder.getService(); + MainActivity.this.mBound = true; + MainActivity.this.state_switch.setChecked(true); + } + + public void onServiceDisconnected(@NotNull ComponentName arg0) { + // Intrinsics.checkNotNullParameter(arg0, "arg0"); + MainActivity.this.mBound = false; + MainActivity.this.state_switch.setChecked(false); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + String versionName = null; + try { + versionName = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + TextView titleText = (TextView)this.findViewById(R.id.titleText); + // Intrinsics.checkNotNullExpressionValue(titleText, "titleText"); + titleText.setText((CharSequence)("frp for Android - " + versionName + "/0.58.0")); + this.checkConfig(); + this.checkNotificationPermission(); + this.createBGNotificationChannel(); + this.mBound = this.isServiceRunning(ShellService.class); + state_switch = (Switch)this.findViewById(R.id.state_switch); + // Intrinsics.checkNotNullExpressionValue(var10001, "findViewById(R.id.state_switch)"); + + state_switch.setChecked(this.mBound); + + state_switch.setOnCheckedChangeListener((CompoundButton.OnCheckedChangeListener)(new CompoundButton.OnCheckedChangeListener() { + public final void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + MainActivity.this.startShell(); + } else { + MainActivity.this.stopShell(); + } + + } + })); + + + final SharedPreferences editor = this.getSharedPreferences("data", 0); + auto_start_switch = (Switch) this.findViewById(R.id.auto_start_switch); + // Intrinsics.checkNotNullExpressionValue(var10001, "findViewById(R.id.auto_start_switch)"); + + auto_start_switch.setChecked(editor.getBoolean("auto_start", false)); + + auto_start_switch.setOnCheckedChangeListener((CompoundButton.OnCheckedChangeListener)(new CompoundButton.OnCheckedChangeListener() { + public final void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + SharedPreferences.Editor editorx = editor.edit(); + editorx.putBoolean("auto_start", isChecked); + editorx.apply(); + } + })); + if (this.mBound) { + Intent intent = new Intent((Context)this, ShellService.class); + this.bindService(intent, (ServiceConnection)this.connection, 1); + } + + this.setListener(); + } + + private final void setListener() { + Button configButton = (Button)this.findViewById(R.id.configButton); + configButton.setOnClickListener((View.OnClickListener)(new View.OnClickListener() { + public final void onClick(View it) { + Intent intent = new Intent((Context)MainActivity.this, ConfigActivity.class); + MainActivity.this.startActivity(intent); + } + })); + + Button refreshButton = (Button)this.findViewById(R.id.refreshButton); + refreshButton.setOnClickListener((View.OnClickListener)(new View.OnClickListener() { + public final void onClick(View it) { + MainActivity.this.readLog(); + } + })); + Button deleteButton = (Button)this.findViewById(R.id.deleteButton); + deleteButton.setOnClickListener((View.OnClickListener)(new View.OnClickListener() { + public final void onClick(View it) { + MainActivity.this.mService.clearOutput(); + MainActivity.this.readLog(); + } + })); + } + + public final void readLog() { + TextView logTextView = (TextView)this.findViewById(R.id.logTextView); + if (this.mBound) { + // Intrinsics.checkNotNullExpressionValue(logTextView, "logTextView"); + ShellService var10001 = this.mService; + if (var10001 == null) { + // Intrinsics.throwUninitializedPropertyAccessException("mService"); + } + + logTextView.setText((CharSequence)var10001.getOutput()); + } else { + Log.w("adx", "readLog mBound==null"); + } + + } + + public final void checkConfig() { + // Intrinsics.checkNotNullExpressionValue(var12, "resources"); + AssetManager assetmanager = getResources().getAssets(); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = this.openFileOutput("config.toml", 0); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + if (fileOutputStream == null) { + return; + } + + InputStream inputStream = null; + byte[] bytes = new byte[256]; + try { + boolean var6 = false; + inputStream = assetmanager.open("config.toml"); + // Intrinsics.checkNotNullExpressionValue(var10001, "assetmanager.open((BuildConfig.ConfigFileName))"); + int bytesRead = inputStream.read(bytes); + if (bytesRead > 0) { + fileOutputStream.write(bytes, 0, bytesRead); + } + // Unit var11 = Unit.INSTANCE; + } catch (Throwable ex) { + ex.printStackTrace(); + } finally { + closeFinally(fileOutputStream); + closeFinally(inputStream); + } + + } + + private static final void closeFinally(Closeable closable) { + if (closable != null) { + try { + closable.close(); + } catch (Throwable var3) { + // ExceptionsKt.addSuppressed(cause, var3); + } + } + } + + private final void startShell() { + Intent intent = new Intent((Context)this, ShellService.class); + intent.putExtra("filename", "libfrpc.so"); + this.startService(intent); + this.bindService(intent, (ServiceConnection)this.connection, Context.BIND_AUTO_CREATE); + } + + private final void stopShell() { + Intent intent = new Intent((Context)this, ShellService.class); + this.unbindService((ServiceConnection)this.connection); + this.stopService(intent); + } + + private final void checkNotificationPermission() { + // Intrinsics.checkNotNullExpressionValue(this.registerForActivityResult((ActivityResultContract)(new RequestPermission()), (ActivityResultCallback)null.INSTANCE), "registerForActivityResul….\n }\n }"); + } + + private final void createBGNotificationChannel() { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + String name = "frp后台服务"; + String descriptionText = "frp后台服务通知"; + NotificationChannel var5 = null; + + var5 = new NotificationChannel("shell_bg", (CharSequence)name, NotificationManager.IMPORTANCE_MIN); + + var5.setDescription(descriptionText); + NotificationChannel channel = var5; + NotificationManager notificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE); + if (notificationManager == null) { + throw new NullPointerException("null cannot be cast to non-null type android.app.NotificationManager"); + } + + notificationManager.createNotificationChannel(channel); + } + + } + + private final boolean isServiceRunning(Class serviceClass) { + ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); + if (activityManager != null) { + Iterator it = activityManager.getRunningServices(Integer.MAX_VALUE).iterator(); + + ComponentName componentName; + String className; + do { + if (!it.hasNext()) { + return false; + } + + ActivityManager.RunningServiceInfo serviceInfo = (ActivityManager.RunningServiceInfo)it.next(); + className = serviceClass.getName(); + componentName = serviceInfo.service; + // Intrinsics.checkNotNullExpressionValue(var10001, "service.service"); + } while(!className.equalsIgnoreCase(componentName.getClassName())); + } + + return true; + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/frpandroid/ShellService.java b/app/src/main/java/com/xypower/frpandroid/ShellService.java new file mode 100644 index 0000000..2cddb90 --- /dev/null +++ b/app/src/main/java/com/xypower/frpandroid/ShellService.java @@ -0,0 +1,157 @@ +package com.xypower.frpandroid; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.support.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Random; + +public class ShellService extends Service { + + private Thread process_thread; + private final StringBuilder outputBuilder = new StringBuilder(); + private final LocalBinder binder = new LocalBinder(); + private final Random mGenerator = new Random(); + + public ShellService() { + } + + @Override + public IBinder onBind(Intent intent) { + // Intrinsics.checkNotNullParameter(intent, "intent"); + return (IBinder)this.binder; + } + + @NotNull + public final String getOutput() { + return this.outputBuilder.toString(); + // Intrinsics.checkNotNullExpressionValue(var10000, "outputBuilder.toString()"); + } + + public final void clearOutput() { + // StringsKt.clear(this.outputBuilder); + // this.outputBuilder. + this.outputBuilder.delete(0, outputBuilder.length()); + } + + public final int getRandomNumber() { + return this.mGenerator.nextInt(100); + } + + + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + String filename = ""; + if (this.process_thread != null) { + Log.w("adx", "process isn't null,service won't start"); + Toast.makeText((Context)this, (CharSequence)"process isn't null,service won't start", Toast.LENGTH_SHORT).show(); + return Service.START_NOT_STICKY; + } else if (intent != null) { + Bundle var10000 = intent.getExtras(); + Object var8 = var10000 != null ? var10000.get("filename") : null; + if (var8 == null) { + throw new NullPointerException("null cannot be cast to non-null type kotlin.String"); + } else { + filename = (String)var8; + ApplicationInfo applicationInfo = null; + try { + applicationInfo = this.getPackageManager().getApplicationInfo(this.getPackageName(), PackageManager.GET_SHARED_LIBRARY_FILES); + } catch (Exception ex) { + + } + // Intrinsics.checkNotNullExpressionValue(var9, "packageManager.getApplic…GET_SHARED_LIBRARY_FILES)"); + Log.d("adx", "native library dir " + applicationInfo.nativeLibraryDir); + + try { + String var10001 = applicationInfo.nativeLibraryDir + '/' + filename + " -c config.toml"; + String[] var10002 = new String[]{""}; + File var10003 = this.getFilesDir(); + // Intrinsics.checkNotNullExpressionValue(var10003, "this.filesDir"); + this.runCommand(var10001, var10002, var10003); + } catch (Exception ex) { + // Log.e("adx", ExceptionsKt.stackTraceToString((Throwable)var7)); + ex.printStackTrace(); + Toast.makeText((Context)this, (CharSequence)ex.getMessage(), Toast.LENGTH_SHORT).show(); + this.stopSelf(); + return Service.START_NOT_STICKY; + } + + Toast.makeText((Context)this, (CharSequence)"已启动frp服务", Toast.LENGTH_SHORT).show(); + this.startForeground(1, this.showMotification()); + return Service.START_NOT_STICKY; + } + } else { + filename = "Error:filename unknown!!!"; + Log.e("adx", filename); + Toast.makeText((Context)this, (CharSequence)filename, Toast.LENGTH_SHORT).show(); + this.stopSelf(); + return Service.START_NOT_STICKY; + } + } + + public void onDestroy() { + Thread var10000 = this.process_thread; + if (var10000 != null) { + var10000.interrupt(); + } + + Toast.makeText((Context)this, (CharSequence)"已关闭frp服务", 0).show(); + } + + private final void runCommand(String command, String[] envp, File dir) { + this.process_thread = new ShellThread(command, envp, dir, new ShellThread.Function1() { + + @Override + public Object invoke(Object var1) { + this.invoke((String)var1); + return null; + // return Unit.INSTANCE; + } + + public final void invoke(@NotNull String it) { + // Intrinsics.checkNotNullParameter(it, "it"); + ShellService.this.outputBuilder.append(it + "\n"); + } + }); + Thread var10000 = this.process_thread; + if (var10000 != null) { + var10000.start(); + } + + } + + private final Notification showMotification() { + Intent var2 = new Intent((Context)this, MainActivity.class); + boolean var4 = false; + PendingIntent var10000 = PendingIntent.getActivity((Context)this, 0, var2, PendingIntent.FLAG_IMMUTABLE); + // Intrinsics.checkNotNullExpressionValue(var10000, "Intent(this, MainActivit…_IMMUTABLE)\n }"); + PendingIntent pendingIntent = var10000; + Notification.Builder var5 = (new Notification.Builder((Context)this, "shell_bg")).setSmallIcon(R.drawable.ic_launcher_foreground).setContentTitle((CharSequence)"frp后台服务").setContentText((CharSequence)"已启动frp").setContentIntent(pendingIntent); + // Intrinsics.checkNotNullExpressionValue(var5, "NotificationCompat.Build…tentIntent(pendingIntent)"); + Notification.Builder notification = var5; + Notification var6 = notification.build(); + // Intrinsics.checkNotNullExpressionValue(var6, "notification.build()"); + return var6; + } + + public final class LocalBinder extends Binder implements IBinder { + @NotNull + public final ShellService getService() { + return ShellService.this; + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/xypower/frpandroid/ShellThread.java b/app/src/main/java/com/xypower/frpandroid/ShellThread.java new file mode 100644 index 0000000..2392e3d --- /dev/null +++ b/app/src/main/java/com/xypower/frpandroid/ShellThread.java @@ -0,0 +1,85 @@ +package com.xypower.frpandroid; + +import org.jetbrains.annotations.NotNull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +public class ShellThread extends Thread { + + public interface Function1 { + Object invoke(Object var1); + } + + @NotNull + private final String command; + @NotNull + private final String[] envp; + @NotNull + private final File dir; + @NotNull + private final Function1 outputCallback; + + + public ShellThread(@NotNull String command, @NotNull String[] envp, @NotNull File dir, @NotNull Function1 outputCallback) { + // Intrinsics.checkNotNullParameter(command, "command"); + // Intrinsics.checkNotNullParameter(envp, "envp"); + // Intrinsics.checkNotNullParameter(dir, "dir"); + // Intrinsics.checkNotNullParameter(outputCallback, "outputCallback"); + super(); + this.command = command; + this.envp = envp; + this.dir = dir; + this.outputCallback = outputCallback; + } + + public void run() { + try { + Process process = Runtime.getRuntime().exec(this.command, this.envp, this.dir); + // Intrinsics.checkNotNullExpressionValue(process, "process"); + InputStream inputStream = process.getInputStream(); + BufferedReader reader = new BufferedReader((Reader)(new InputStreamReader(inputStream))); + + while(true) { + String var5 = reader.readLine(); + if (var5 == null || this.isInterrupted()) { + reader.close(); + process.destroy(); + break; + } + + if (var5 != null) { + this.outputCallback.invoke(var5); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + + } + + @NotNull + public final String getCommand() { + return this.command; + } + + @NotNull + public final String[] getEnvp() { + return this.envp; + } + + @NotNull + public final File getDir() { + return this.dir; + } + + @NotNull + public final Function1 getOutputCallback() { + return this.outputCallback; + } + +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_config.xml b/app/src/main/res/layout/activity_config.xml new file mode 100644 index 0000000..8b771fd --- /dev/null +++ b/app/src/main/res/layout/activity_config.xml @@ -0,0 +1,39 @@ + + + + + +