diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6214df7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/ + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..672a34e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,38 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + defaultConfig { + applicationId "com.example.yentencoin.yentenminer" + minSdkVersion 21 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + flavorDimensions 'default' + productFlavors { + standard { + } + kitkat { + minSdkVersion 19 + } + } +} + +dependencies { + implementation project(':bitzenymininglibrary') + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'com.microsoft.appcenter:espresso-test-extension:1.2' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /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 diff --git a/app/src/androidTest/java/com/example/ottylab/bitzenyminer/MainActivityTest.java b/app/src/androidTest/java/com/example/ottylab/bitzenyminer/MainActivityTest.java new file mode 100644 index 0000000..867179e --- /dev/null +++ b/app/src/androidTest/java/com/example/ottylab/bitzenyminer/MainActivityTest.java @@ -0,0 +1,104 @@ +package com.example.ottylab.bitzenyminer; + + +import android.support.test.espresso.ViewInteraction; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; + +import com.microsoft.appcenter.espresso.Factory; +import com.microsoft.appcenter.espresso.ReportHelper; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withClassName; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class MainActivityTest { + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Rule + public ReportHelper reportHelper = Factory.getReportHelper(); + + @After + public void TearDown(){ + reportHelper.label("Stopping App"); + } + + @Test + public void mainActivityTest() { + ViewInteraction appCompatCheckBox = onView( + allOf(withId(R.id.checkBoxBenchmark), withText("Benchmark"), + childAtPosition( + childAtPosition( + withClassName(is("android.widget.LinearLayout")), + 4), + 1), + isDisplayed())); + appCompatCheckBox.perform(click()); + + ViewInteraction appCompatButton = onView( + allOf(withId(R.id.buttonDrive), withText("Start"), + childAtPosition( + childAtPosition( + withClassName(is("android.widget.LinearLayout")), + 4), + 0), + isDisplayed())); + appCompatButton.perform(click()); + + try{ + Thread.sleep(5000); + } catch (InterruptedException e){} + + ViewInteraction textView = onView( + allOf(withId(R.id.textViewLog), + childAtPosition( + childAtPosition( + withId(android.R.id.content), + 0), + 5), + isDisplayed())); + textView.check(matches(withText(containsString("miner threads started, using 'yescrypt' algorithm.")))); + } + + private static Matcher childAtPosition( + final Matcher parentMatcher, final int position) { + + return new TypeSafeMatcher() { + @Override + public void describeTo(Description description) { + description.appendText("Child at position " + position + " in parent "); + parentMatcher.describeTo(description); + } + + @Override + public boolean matchesSafely(View view) { + ViewParent parent = view.getParent(); + return parent instanceof ViewGroup && parentMatcher.matches(parent) + && view.equals(((ViewGroup) parent).getChildAt(position)); + } + }; + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0e1c2c2 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/ottylab/bitzenyminer/MainActivity.java b/app/src/main/java/com/example/ottylab/bitzenyminer/MainActivity.java new file mode 100644 index 0000000..1efdba1 --- /dev/null +++ b/app/src/main/java/com/example/ottylab/bitzenyminer/MainActivity.java @@ -0,0 +1,200 @@ +package com.example.ottylab.bitzenyminer; + +import android.content.SharedPreferences; +import android.os.Build; +import android.os.Handler; +import android.os.Message; +import android.preference.PreferenceManager; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; + +import com.example.ottylab.bitzenymininglibrary.BitZenyMiningLibrary; + +import java.lang.ref.WeakReference; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class MainActivity extends AppCompatActivity { + private static final String TAG = "BitZenyMiner"; + private static final int LOG_LINES = 1000; + + private BitZenyMiningLibrary miner; + + private EditText editTextServer; + private EditText editTextUser; + private EditText editTextPassword; + private EditText editTextNThreads; + private Button buttonDrive; + private CheckBox checkBoxBenchmark; + private Spinner spinnerAlgorithm; + private TextView textViewLog; + + private boolean running; + private BlockingQueue logs = new LinkedBlockingQueue<>(LOG_LINES); + + private static class JNICallbackHandler extends Handler { + private final WeakReference activity; + + public JNICallbackHandler(MainActivity activity) { + this.activity = new WeakReference(activity); + } + + @Override + public void handleMessage(Message msg) { + MainActivity activity = this.activity.get(); + if (activity != null) { + String log = msg.getData().getString("log"); + String logs = Utils.rotateStringQueue(activity.logs, log); + activity.textViewLog.setText(logs); + Log.d(TAG, log); + } + } + } + + private static JNICallbackHandler sHandler; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + showDeviceInfo(); + + sHandler = new JNICallbackHandler(this); + miner = new BitZenyMiningLibrary(sHandler); + + editTextServer = (EditText) findViewById(R.id.editTextServer); + editTextServer.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean b) { + storeSetting(); + } + }); + + editTextUser = (EditText) findViewById(R.id.editTextUser); + editTextUser.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean b) { + storeSetting(); + } + }); + + editTextPassword= (EditText) findViewById(R.id.editTextPassword); + editTextPassword.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean b) { + storeSetting(); + } + }); + + editTextNThreads = (EditText) findViewById(R.id.editTextNThreads); + editTextNThreads.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean b) { + storeSetting(); + } + }); + + buttonDrive = (Button) findViewById(R.id.buttonDrive); + buttonDrive.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (running) { + Log.d(TAG, "Stop"); + miner.stopMining(); + } else { + Log.d(TAG, "Start"); + int n_threads = 0; + try { + n_threads = Integer.parseInt(editTextNThreads.getText().toString()); + } catch (NumberFormatException e){} + + BitZenyMiningLibrary.Algorithm algorithm = + spinnerAlgorithm.getSelectedItemPosition() == 0 ? + BitZenyMiningLibrary.Algorithm.YESCRYPT : BitZenyMiningLibrary.Algorithm.YESPOWER; + if (checkBoxBenchmark.isChecked()) { + miner.startBenchmark(n_threads, algorithm); + } else { + miner.startMining( + editTextServer.getText().toString(), + editTextUser.getText().toString(), + editTextPassword.getText().toString(), + n_threads, + algorithm); + } + } + + changeState(!running); + storeSetting(); + } + }); + + checkBoxBenchmark = (CheckBox) findViewById(R.id.checkBoxBenchmark); + spinnerAlgorithm = (Spinner) findViewById(R.id.spinnerAlgorithm); + ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.algorithms, android.R.layout.simple_spinner_item); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinnerAlgorithm.setAdapter(adapter); + + textViewLog = (TextView) findViewById(R.id.textViewLog); + textViewLog.setMovementMethod(new ScrollingMovementMethod()); + + restoreSetting(); + changeState(miner.isMiningRunning()); + } + + private void changeState(boolean running) { + buttonDrive.setText(running ? "Stop" : "Start"); + disableSetting(running); + this.running = running; + } + + private void disableSetting(boolean running) { + editTextServer.setEnabled(!running); + editTextUser.setEnabled(!running); + editTextPassword.setEnabled(!running); + editTextNThreads.setEnabled(!running); + spinnerAlgorithm.setEnabled(!running); + } + + private void storeSetting() { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = pref.edit(); + editor.putString("server", editTextServer.getText().toString()); + editor.putString("user", editTextUser.getText().toString()); + editor.putString("password", editTextPassword.getText().toString()); + editor.putString("n_threads", editTextNThreads.getText().toString()); + editor.putInt("algorithm", spinnerAlgorithm.getSelectedItemPosition()); + editor.commit(); + } + + private void restoreSetting() { + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); + editTextServer.setText(pref.getString("server", null)); + editTextUser.setText(pref.getString("user", null)); + editTextPassword.setText(pref.getString("password", null)); + editTextNThreads.setText(pref.getString("n_threads", null)); + spinnerAlgorithm.setSelection(pref.getInt("algorithm", 0)); + } + + private void showDeviceInfo() { + String[] keys = new String[]{ "os.arch", "os.name", "os.version" }; + for (String key : keys) { + Log.d(TAG, key + ": " + System.getProperty(key)); + } + Log.d(TAG, "CODE NAME: " + Build.VERSION.CODENAME); + Log.d(TAG, "SDK INT: " + Build.VERSION.SDK_INT); + Log.d(TAG, "MANUFACTURER: " + Build.MANUFACTURER); + Log.d(TAG, "MODEL: " + Build.MODEL); + Log.d(TAG, "PRODUCT: " + Build.PRODUCT); + } +} diff --git a/app/src/main/java/com/example/ottylab/bitzenyminer/Utils.java b/app/src/main/java/com/example/ottylab/bitzenyminer/Utils.java new file mode 100644 index 0000000..07f8355 --- /dev/null +++ b/app/src/main/java/com/example/ottylab/bitzenyminer/Utils.java @@ -0,0 +1,26 @@ +package com.example.ottylab.bitzenyminer; + +import java.util.concurrent.BlockingQueue; + +/** + * Created by ochikage on 2018/02/18. + */ + +public class Utils { + public static String rotateStringQueue(BlockingQueue queue, String next) { + while (!queue.offer(next)) { + try { + queue.take(); + } catch (InterruptedException e){ + ; + } + } + + StringBuilder logs = new StringBuilder(); + for (String element: queue) { + logs.append(element); + } + + return logs.toString(); + } +} 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..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + 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..d5fccc5 --- /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_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..971ee29 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + +