├── .gitignore ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro ├── release │ └── app-release.apk └── src │ ├── androidTest │ └── java │ │ └── org │ │ └── aeon │ │ └── aeondaemon │ │ └── app │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── org │ │ │ └── aeon │ │ │ └── aeondaemon │ │ │ └── app │ │ │ ├── AboutActivity.java │ │ │ ├── AppCompatPreferenceActivity.java │ │ │ ├── Fragments │ │ │ ├── LogSlideFragment.java │ │ │ └── MainSlideFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── SettingsPrefActivity.java │ │ │ ├── ThemeActivity.java │ │ │ └── model │ │ │ ├── CollectPreferences.java │ │ │ ├── Launcher.java │ │ │ ├── Settings.java │ │ │ └── SynchronizeThread.java │ └── res │ │ ├── drawable │ │ ├── actionbar.png │ │ ├── background.png │ │ ├── coins.png │ │ ├── coinscolor.png │ │ ├── mic_launcher.png │ │ ├── mythbar.png │ │ ├── mythology.png │ │ ├── oval_selected.xml │ │ ├── oval_unselected.xml │ │ ├── solidcolor.png │ │ ├── w001.png │ │ ├── wcoin.png │ │ ├── wowario.jpg │ │ └── wsolidcolor.png │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_main.xml │ │ ├── activity_settings.xml │ │ ├── activity_theme.xml │ │ ├── log_fragment.xml │ │ └── main_fragment.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── wic_launcher.png │ │ └── wic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── wic_launcher.png │ │ └── wic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── wic_launcher.png │ │ └── wic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── wic_launcher.png │ │ └── wic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── wic_launcher.png │ │ └── wic_launcher_round.png │ │ ├── raw │ │ ├── monerod32 │ │ └── monerod64 │ │ ├── values-fr │ │ └── strings.xml │ │ ├── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── arrays.xml │ │ ├── pref_about.xml │ │ ├── pref_settings.xml │ │ └── pref_theme.xml │ └── test │ └── java │ └── org │ └── aeon │ └── aeondaemon │ └── app │ └── ExampleUnitTest.java ├── assets └── pocketnode-inspiration.png ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat ├── monero-logo.svg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | local.properties 2 | build 3 | gradle 4 | .gradle 5 | .idea 6 | .vscode 7 | app/release/* 8 | *.jks 9 | keystore.jks 10 | scripts -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Archiving this project 10/16/23: This project is no longer being maintained. Forks welcome. 2 | 3 | 4 | # Monero PocketNode - A Monero node for your Android Device. 5 | 6 | ## Overview 7 | 8 | THIS IS A WORK IN PROGRESS. USE AT YOUR OWN RISK. PR'S/FORKS WELCOME! RECOMMEND USING ON AN OLD PHONE- NOT YOUR DAILY DRIVER. I DON'T KNOW HOW TO WRITE ANDROID APPS. 9 | 10 | This app is meant first and foremost for people with Android phones that have SD slots that are laying in a drawer that can be repurposed into a constantly-plugged-in, extremely low power node. I don't recommend using this on internal storage (though I am using this myself)... You're taking the internal SSD life into your own hands if you use this feature. 11 | 12 | Important things that probably don't work: 13 | 14 | 1. Syncing with the screen off with the phone UNPLUGGED (it SHOULD continue syncing when plugged in). You can download an app called 'Coffee' if you need to have the phone continue syncing while not plugged in. 15 | 16 | ## Device requirements 17 | A 64 bit processor with 2 GB of RAM and for storage, an SD slot or 128 GB of internal storage is recommended to run on the mainnet blockchain. 18 | 19 | ## Install 20 | 21 | Important: After installing, be sure to turn of Android battery optimization for this app, otherwise Android will auto stop it after awhile. 22 | It's typically found somewhere like: Settings > Apps > Pocket Node > App Battery Usage > Turn on Unrestricted (not Optimized). 23 | 24 | ### Secure Install 25 | Download Android Studio, replace the monero64/32 binaries with your own Android ARMv7/v8 binaries and generate a signed .apk. 26 | 27 | OR 28 | 29 | ### Just Trust CryptoGrampy Simple Install 30 | (If you trust that I haven't added nefarious binaries) Download the .apk from the (latest release)[https://github.com/CryptoGrampy/xmr-pocket-node/releases], and start up the app. 31 | 32 | ## Run it 33 | 34 | Again, first make sure battery optimization is turned off or set to unrestricted for PocketNode. 35 | 36 | To Start the node- hit the toggle on the Main screen. Check out the settings menu for more fine-grained control over your Node. That's it! 37 | 38 | You can also expose your new node as a Tor hidden service by downloading Orbot from FDroid, and going through their create hidden service feature in the top right corner. Point the hidden service service at port 18081 (this is your node's RPC port), and you can expose whatever port you want- 80, 18081, etc. 39 | 40 | ## Donate 41 | 42 | If you want to buy coffee for an 85 year old: 8BudmXKZwpXhfVGCtgFPyKWgLcDLYJ5jRT95xCp4JMFWapgTLrun41AG6LPbef7WFA8T531QGnZT51cDF6uF9HECDhibEVw 43 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "org.cryptogrampy.pocketnode.app" 7 | minSdkVersion 21 8 | targetSdkVersion 27 9 | versionCode 6 10 | versionName "0.5.0-alpha" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | lint { 20 | abortOnError false 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation 'com.android.support:appcompat-v7:27.1.1' 27 | implementation 'com.android.support:design:27.1.1' 28 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 29 | testImplementation 'junit:junit:4.12' 30 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 32 | } 33 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/release/app-release.apk -------------------------------------------------------------------------------- /app/src/androidTest/java/org/aeon/aeondaemon/app/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package org.aeon.aeondaemon.app; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("org.aeon.aeondaemon.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/AboutActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app; 17 | 18 | import android.app.AlertDialog; 19 | import android.content.ClipData; 20 | import android.content.ClipboardManager; 21 | import android.content.Context; 22 | import android.content.DialogInterface; 23 | import android.graphics.drawable.ColorDrawable; 24 | import android.os.Build; 25 | import android.os.Bundle; 26 | import android.support.v4.content.ContextCompat; 27 | import android.support.v7.app.ActionBar; 28 | import android.text.method.LinkMovementMethod; 29 | import android.view.MenuItem; 30 | import android.view.View; 31 | import android.widget.TextView; 32 | 33 | public class AboutActivity extends AppCompatPreferenceActivity { 34 | private static final String TAG = AboutActivity.class.getSimpleName(); 35 | private Context context = null; 36 | 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | context = getApplicationContext(); 42 | 43 | setContentView(R.layout.activity_about); 44 | MainActivity.setAboutActivity(this); 45 | 46 | TextView t = ((TextView)findViewById(R.id.xmr_msg_val)); 47 | t.setOnClickListener(copyListener); 48 | 49 | t = ((TextView)findViewById(R.id.xmr_msg_val)); 50 | t.setOnClickListener(copyListener); 51 | 52 | t = ((TextView)findViewById(R.id.about_msg)); 53 | t.setMovementMethod(LinkMovementMethod.getInstance()); 54 | 55 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 56 | getSupportActionBar().setHomeButtonEnabled(true); 57 | getSupportActionBar().setDisplayShowHomeEnabled(true); 58 | 59 | setTheme(MainActivity.getStyle(context)); 60 | } 61 | 62 | 63 | private View.OnClickListener copyListener = new View.OnClickListener() { 64 | public void onClick(View v) { 65 | ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); 66 | ClipData clip = ClipData.newPlainText("label",((TextView)v).getText()); 67 | clipboard.setPrimaryClip(clip); 68 | 69 | AlertDialog.Builder builder; 70 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 71 | builder = new AlertDialog.Builder(AboutActivity.this, android.R.style.Theme_Material_Dialog_Alert); 72 | } else { 73 | builder = new AlertDialog.Builder(AboutActivity.this); 74 | } 75 | builder.setTitle("Clipboard") 76 | .setMessage(R.string.address_selected_msg) 77 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 78 | public void onClick(DialogInterface dialog, int which) { 79 | } 80 | }) 81 | .setIcon(android.R.drawable.ic_dialog_alert) 82 | .show(); 83 | } 84 | }; 85 | 86 | @Override 87 | public boolean onOptionsItemSelected(MenuItem item) { 88 | if (item.getItemId() == android.R.id.home) { 89 | onBackPressed(); 90 | } 91 | return super.onOptionsItemSelected(item); 92 | } 93 | 94 | @Override 95 | public void onResume(){ 96 | super.onResume(); 97 | 98 | setTheme(MainActivity.getStyle(context)); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/AppCompatPreferenceActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app; 17 | 18 | import android.content.res.Configuration; 19 | import android.os.Bundle; 20 | import android.preference.PreferenceActivity; 21 | import android.support.annotation.LayoutRes; 22 | import android.support.annotation.Nullable; 23 | import android.support.v4.content.ContextCompat; 24 | import android.support.v7.app.ActionBar; 25 | import android.support.v7.app.AppCompatDelegate; 26 | import android.support.v7.widget.Toolbar; 27 | import android.view.MenuInflater; 28 | import android.view.View; 29 | import android.view.ViewGroup; 30 | 31 | public abstract class AppCompatPreferenceActivity extends PreferenceActivity { 32 | 33 | private AppCompatDelegate mDelegate; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | getDelegate().installViewFactory(); 38 | getDelegate().onCreate(savedInstanceState); 39 | 40 | setTheme(MainActivity.getStyle(getApplicationContext())); 41 | 42 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 43 | getSupportActionBar().setHomeButtonEnabled(true); 44 | getSupportActionBar().setDisplayShowHomeEnabled(true); 45 | 46 | super.onCreate(savedInstanceState); 47 | } 48 | 49 | @Override 50 | protected void onPostCreate(Bundle savedInstanceState) { 51 | super.onPostCreate(savedInstanceState); 52 | getDelegate().onPostCreate(savedInstanceState); 53 | } 54 | 55 | public ActionBar getSupportActionBar() { 56 | return getDelegate().getSupportActionBar(); 57 | } 58 | 59 | public void setSupportActionBar(@Nullable Toolbar toolbar) { 60 | getDelegate().setSupportActionBar(toolbar); 61 | } 62 | 63 | @Override 64 | public MenuInflater getMenuInflater() { 65 | return getDelegate().getMenuInflater(); 66 | } 67 | 68 | @Override 69 | public void setContentView(@LayoutRes int layoutResID) { 70 | getDelegate().setContentView(layoutResID); 71 | } 72 | 73 | @Override 74 | public void setContentView(View view) { 75 | getDelegate().setContentView(view); 76 | } 77 | 78 | @Override 79 | public void setContentView(View view, ViewGroup.LayoutParams params) { 80 | getDelegate().setContentView(view, params); 81 | } 82 | 83 | @Override 84 | public void addContentView(View view, ViewGroup.LayoutParams params) { 85 | getDelegate().addContentView(view, params); 86 | } 87 | 88 | @Override 89 | protected void onPostResume() { 90 | super.onPostResume(); 91 | getDelegate().onPostResume(); 92 | } 93 | 94 | @Override 95 | protected void onTitleChanged(CharSequence title, int color) { 96 | super.onTitleChanged(title, color); 97 | getDelegate().setTitle(title); 98 | } 99 | 100 | @Override 101 | public void onConfigurationChanged(Configuration newConfig) { 102 | super.onConfigurationChanged(newConfig); 103 | getDelegate().onConfigurationChanged(newConfig); 104 | } 105 | 106 | @Override 107 | protected void onStop() { 108 | super.onStop(); 109 | getDelegate().onStop(); 110 | } 111 | 112 | @Override 113 | protected void onDestroy() { 114 | super.onDestroy(); 115 | getDelegate().onDestroy(); 116 | } 117 | 118 | public void invalidateOptionsMenu() { 119 | getDelegate().invalidateOptionsMenu(); 120 | } 121 | 122 | private AppCompatDelegate getDelegate() { 123 | if (mDelegate == null) { 124 | mDelegate = AppCompatDelegate.create(this, null); 125 | } 126 | return mDelegate; 127 | } 128 | } -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/Fragments/LogSlideFragment.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app.Fragments; 17 | 18 | import android.app.AlertDialog; 19 | import android.content.ClipData; 20 | import android.content.ClipboardManager; 21 | import android.content.Context; 22 | import android.content.DialogInterface; 23 | import android.os.Build; 24 | import android.os.Bundle; 25 | import android.os.Handler; 26 | import android.support.v4.app.Fragment; 27 | import android.text.Selection; 28 | import android.text.SpannableString; 29 | import android.text.method.ScrollingMovementMethod; 30 | import android.view.LayoutInflater; 31 | import android.view.View; 32 | import android.view.ViewGroup; 33 | import android.widget.ScrollView; 34 | import android.widget.TextView; 35 | 36 | import org.aeon.aeondaemon.app.MainActivity; 37 | import org.aeon.aeondaemon.app.R; 38 | import org.aeon.aeondaemon.app.model.Launcher; 39 | import org.aeon.aeondaemon.app.model.SynchronizeThread; 40 | 41 | public class LogSlideFragment extends Fragment { 42 | private static final String TAG = LogSlideFragment.class.getSimpleName(); 43 | private static long RefreshInterval = 1000; 44 | private ViewGroup rootView; 45 | private Context context = null; 46 | 47 | @Override 48 | public void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | 51 | final Handler handler = new Handler(); 52 | 53 | Runnable r = new Runnable() { 54 | @Override 55 | public void run() { 56 | ScrollView s = (ScrollView) rootView.findViewById(R.id.logs_scrollview); 57 | 58 | boolean hasFocus = MainActivity.getmViewPager().getCurrentItem() == MainActivity.FRAGMENT_LOG; 59 | if (hasFocus) { 60 | Launcher launcher = SynchronizeThread.getLauncher(); 61 | if (launcher == null) { 62 | TextView v = (TextView) rootView.findViewById(R.id.logs); 63 | v.setText(getString(R.string.daemon_not_running)); 64 | } else { 65 | launcher.updateStatus(); 66 | 67 | /** 68 | * Autoscrolling text 69 | * https://stackoverflow.com/questions/3506696/auto-scrolling-textview-in-android-to-bring-text-into-view 70 | */ 71 | TextView v = (TextView) rootView.findViewById(R.id.logs); 72 | v.setMovementMethod(new ScrollingMovementMethod()); 73 | 74 | SpannableString spannable = new SpannableString(launcher.getLogs()); 75 | Selection.setSelection(spannable, spannable.length()); 76 | v.setText(spannable, TextView.BufferType.SPANNABLE); 77 | s.fullScroll(ScrollView.FOCUS_DOWN); 78 | } 79 | } 80 | handler.postDelayed(this, RefreshInterval); 81 | } 82 | }; 83 | handler.postDelayed(r, RefreshInterval); 84 | } 85 | 86 | @Override 87 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 88 | rootView = (ViewGroup) inflater.inflate(R.layout.log_fragment, container, false); 89 | ((TextView) rootView.findViewById(R.id.logs)).setOnLongClickListener(copyListener); 90 | 91 | return rootView; 92 | } 93 | 94 | @Override 95 | public void onViewCreated(View view, Bundle savedInstanceState) { 96 | super.onViewCreated(view, savedInstanceState); 97 | } 98 | 99 | 100 | private View.OnLongClickListener copyListener = new View.OnLongClickListener() { 101 | public boolean onLongClick(View v) { 102 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); 103 | ClipData clip = ClipData.newPlainText("label", ((TextView) v).getText()); 104 | clipboard.setPrimaryClip(clip); 105 | 106 | AlertDialog.Builder builder; 107 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 108 | builder = new AlertDialog.Builder(context, android.R.style.Theme_Material_Dialog_Alert); 109 | } else { 110 | builder = new AlertDialog.Builder(context); 111 | } 112 | builder.setTitle("Clipboard") 113 | .setMessage(R.string.logs_selected_msg) 114 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 115 | public void onClick(DialogInterface dialog, int which) { 116 | } 117 | }) 118 | .setIcon(android.R.drawable.ic_dialog_alert) 119 | .show(); 120 | return true; 121 | } 122 | }; 123 | 124 | @Override 125 | public void onAttach(Context _context) { 126 | super.onAttach(_context); 127 | context = _context; 128 | } 129 | } -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/Fragments/MainSlideFragment.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app.Fragments; 17 | 18 | import static org.aeon.aeondaemon.app.model.CollectPreferences.collectedPreferences; 19 | import static java.lang.Integer.parseInt; 20 | 21 | import android.app.Activity; 22 | import android.app.AlertDialog; 23 | import android.content.Context; 24 | import android.content.DialogInterface; 25 | import android.content.SharedPreferences; 26 | import android.net.wifi.WifiManager; 27 | import android.os.Build; 28 | import android.os.Bundle; 29 | import android.os.Handler; 30 | import android.preference.PreferenceManager; 31 | import android.support.v4.app.Fragment; 32 | import android.support.v4.content.ContextCompat; 33 | import android.support.v7.widget.SwitchCompat; 34 | import android.text.format.Formatter; 35 | import android.util.Log; 36 | import android.view.LayoutInflater; 37 | import android.view.View; 38 | import android.view.ViewGroup; 39 | import android.widget.TextView; 40 | 41 | import org.aeon.aeondaemon.app.MainActivity; 42 | import org.aeon.aeondaemon.app.R; 43 | import org.aeon.aeondaemon.app.model.CollectPreferences; 44 | import org.aeon.aeondaemon.app.model.Launcher; 45 | import org.aeon.aeondaemon.app.model.SynchronizeThread; 46 | 47 | import java.io.File; 48 | 49 | public class MainSlideFragment extends Fragment { 50 | private static final String TAG = MainSlideFragment.class.getSimpleName(); 51 | private static long RefreshInterval = 1000; 52 | public static String execError = null; 53 | private ViewGroup rootView; 54 | private Context context = null; 55 | private static boolean hasCriticalError = false; 56 | private static SharedPreferences sharedPreferences; 57 | private static SwitchCompat nodeSwitch; 58 | 59 | 60 | @Override 61 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 62 | rootView = (ViewGroup) inflater.inflate(R.layout.main_fragment, container, false); 63 | context = getActivity(); 64 | setDisconnectedValues(); 65 | 66 | final Handler handler = new Handler(); 67 | 68 | Runnable r = new Runnable() { 69 | @Override 70 | public void run() { 71 | doUpdate(); 72 | handler.postDelayed( this, RefreshInterval ); 73 | } 74 | }; 75 | handler.postDelayed(r,RefreshInterval); 76 | 77 | TextView v = (TextView) rootView.findViewById(R.id.sync_status); 78 | v.setText(getActivity().getString(R.string.daemon_not_running)); 79 | 80 | /** 81 | * On init, set switch to saved setting or use default 82 | * 83 | * on update, check node setting, update node status, update saved setting 84 | * 85 | */ 86 | nodeSwitch = (SwitchCompat) rootView.findViewById(R.id.enable_node); 87 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); 88 | initEnableNode(); 89 | 90 | return rootView; 91 | } 92 | 93 | /** 94 | * Sets the enable_node Switch with the last saved state of the button 95 | * defaults to false 96 | * and actually enables the node if previous state was true 97 | */ 98 | private void initEnableNode() { 99 | Boolean t = sharedPreferences.getBoolean("enable_node", false); 100 | SwitchCompat nodeSwitch = (SwitchCompat) rootView.findViewById(R.id.enable_node); 101 | nodeSwitch.setChecked(t.booleanValue()); 102 | collectedPreferences.setEnableNode(t.booleanValue()); 103 | } 104 | 105 | /** 106 | * Saves the toggle state of the button to be loaded on app restart 107 | * and actually turns on the node 108 | */ 109 | private void updateEnableNode() { 110 | collectedPreferences.setEnableNode(nodeSwitch.isChecked()); 111 | SharedPreferences.Editor editor = sharedPreferences.edit(); 112 | editor.putBoolean("enable_node", nodeSwitch.isChecked()); 113 | editor.commit(); 114 | } 115 | 116 | private void doUpdate() { 117 | boolean hasFocus = MainActivity.getmViewPager().getCurrentItem() == MainActivity.FRAGMENT_MAIN; 118 | if (hasFocus) { 119 | if (hasCriticalError) { 120 | Log.d(TAG,"hasCriticalError"); 121 | return; 122 | } 123 | if (execError != null) { 124 | if(!((Activity) context).isFinishing()) { 125 | AlertDialog.Builder builder; 126 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 127 | builder = new AlertDialog.Builder(context, android.R.style.Theme_Material_Dialog_Alert); 128 | } else { 129 | builder = new AlertDialog.Builder(context); 130 | } 131 | builder.setTitle("monerod") 132 | .setMessage(execError) 133 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 134 | public void onClick(DialogInterface dialog, int which) { 135 | } 136 | }) 137 | .setIcon(android.R.drawable.ic_dialog_alert) 138 | .show(); 139 | } 140 | execError = null; 141 | hasCriticalError = true; 142 | } 143 | 144 | updateEnableNode(); 145 | 146 | 147 | Launcher launcher = SynchronizeThread.getLauncher(); 148 | 149 | if (launcher == null) { 150 | TextView v = (TextView) rootView.findViewById(R.id.sync_status); 151 | v.setText(R.string.daemon_not_running); 152 | }; 153 | 154 | if (launcher.isStarting()) { 155 | TextView v = (TextView) rootView.findViewById(R.id.sync_status); 156 | v.setText(context.getString(R.string.sync_starting)); 157 | } else if (launcher.isAlive()) { 158 | TextView v = (TextView) rootView.findViewById(R.id.heightValue); 159 | String height = launcher.getHeight(); 160 | if (height != null) { 161 | v.setText("Height: " + height); 162 | } 163 | 164 | v = (TextView) rootView.findViewById(R.id.heightTarget); 165 | String targetHeight = launcher.getTarget(); 166 | 167 | if (targetHeight != null) { 168 | v.setText("Target Height: " + targetHeight); 169 | } 170 | 171 | v = (TextView) rootView.findViewById(R.id.syncPercentage); 172 | if (launcher.getSyncPercentage() != null) { 173 | v.setText("Sync Progress: " + launcher.getSyncPercentage() + "%"); 174 | } 175 | 176 | v = (TextView) rootView.findViewById(R.id.compiledMsgAeonVersion); 177 | if (launcher.getVersion() != null) v.setText(launcher.getVersion()); 178 | 179 | v = (TextView) rootView.findViewById(R.id.peers); 180 | if (launcher.getPeers() != null) 181 | v.setText(launcher.getPeers() + " " + context.getString(R.string.msg_peers_connected)); 182 | 183 | v = (TextView) rootView.findViewById(R.id.downloading); 184 | if (launcher.getDownloading() != null) 185 | v.setText(context.getString(R.string.download_at) + " " + launcher.getDownloading() + " kB/s"); 186 | 187 | v = (TextView) rootView.findViewById(R.id.disk); 188 | String s = String.format("%.1f", getUsedSpace()); 189 | v.setText(s + " " + context.getString(R.string.disk_used)); 190 | 191 | v = (TextView) rootView.findViewById(R.id.sync_status); 192 | v.setText(R.string.daemon_running); 193 | 194 | v = (TextView) rootView.findViewById(R.id.local_ip_address); 195 | int port = collectedPreferences.getRpcBindPort(); 196 | v.setText("Node Address: "+getLocalIpAddress()+(port > 0 ? (":"+port) : ":18081")); 197 | 198 | } else { 199 | // Unset all Main page values by default 200 | setDisconnectedValues(); 201 | } 202 | } 203 | } 204 | 205 | private void setDisconnectedValues() { 206 | TextView v = (TextView) rootView.findViewById(R.id.heightValue); 207 | v.setText(""); 208 | 209 | v = (TextView) rootView.findViewById(R.id.heightTarget); 210 | v.setText(""); 211 | 212 | v = (TextView) rootView.findViewById(R.id.syncPercentage); 213 | v.setText(""); 214 | 215 | v = (TextView) rootView.findViewById(R.id.compiledMsgAeonVersion); 216 | v.setText(""); 217 | 218 | v = (TextView) rootView.findViewById(R.id.peers); 219 | v.setText(""); 220 | 221 | v = (TextView) rootView.findViewById(R.id.downloading); 222 | v.setText(""); 223 | 224 | v = (TextView) rootView.findViewById(R.id.disk); 225 | v.setText(""); 226 | 227 | v = (TextView) rootView.findViewById(R.id.sync_status); 228 | v.setText(R.string.daemon_not_running); 229 | 230 | v = (TextView) rootView.findViewById(R.id.local_ip_address); 231 | v.setText(""); 232 | } 233 | 234 | private String getLocalIpAddress() { 235 | WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 236 | String ipAddress = Formatter.formatIpAddress(wifiManager.getConnectionInfo().getIpAddress()); 237 | return ipAddress; 238 | } 239 | 240 | /** 241 | * Get availabe free space on the disk 242 | * 243 | * @return percentage of free space. 244 | */ 245 | private float getUsedSpace() { 246 | File f = new File(collectedPreferences.isUseSDCard() ? collectedPreferences.getSdCardPath() : MainActivity.BINARY_PATH); 247 | return f.getFreeSpace() / 1024.0f / 1024.0f / 1024.0f; 248 | } 249 | 250 | @Override 251 | public void onResume(){ 252 | super.onResume(); 253 | } 254 | 255 | @Override 256 | public void onAttach(Context _context) { 257 | super.onAttach(_context); 258 | context = _context; 259 | } 260 | 261 | public static void setHasCriticalError(boolean _hasCriticalError) { 262 | hasCriticalError = _hasCriticalError; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app; 17 | 18 | import android.app.AlertDialog; 19 | import android.content.Context; 20 | import android.content.DialogInterface; 21 | import android.content.Intent; 22 | import android.content.SharedPreferences; 23 | import android.content.res.Resources; 24 | import android.graphics.drawable.ColorDrawable; 25 | import android.os.Bundle; 26 | import android.os.PowerManager; 27 | import android.preference.PreferenceManager; 28 | import android.support.v4.app.FragmentManager; 29 | import android.support.v4.app.FragmentPagerAdapter; 30 | import android.support.v4.content.ContextCompat; 31 | import android.support.v4.view.ViewPager; 32 | import android.support.v7.app.ActionBar; 33 | import android.support.v7.app.AppCompatActivity; 34 | import android.util.Log; 35 | import android.view.Menu; 36 | import android.view.MenuItem; 37 | import android.os.Build; 38 | 39 | import org.aeon.aeondaemon.app.Fragments.LogSlideFragment; 40 | import org.aeon.aeondaemon.app.Fragments.MainSlideFragment; 41 | import org.aeon.aeondaemon.app.model.SynchronizeThread; 42 | 43 | import java.io.File; 44 | import java.io.FileOutputStream; 45 | import java.io.IOException; 46 | import java.io.InputStream; 47 | import java.io.OutputStream; 48 | 49 | public class MainActivity extends AppCompatActivity { 50 | private static final String TAG = MainActivity.class.getSimpleName(); 51 | public static String BINARY_PATH = null; 52 | public static String PACKAGE_NAME; 53 | public static int FRAGMENT_MAIN=0; 54 | public static int FRAGMENT_LOG=1; 55 | private static AppCompatPreferenceActivity logActivity; 56 | private static AppCompatPreferenceActivity aboutActivity; 57 | private static AppCompatPreferenceActivity themeActivity; 58 | private static boolean initDone = false; 59 | private static ViewPager mViewPager; 60 | private SectionsPagerAdapter mSectionsPagerAdapter; 61 | private SynchronizeThread synchronizeThread = null; 62 | private static Context context = null; 63 | private PowerManager.WakeLock wakelock; 64 | 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | 69 | PACKAGE_NAME = getApplicationContext().getPackageName(); 70 | context = getApplicationContext(); 71 | 72 | // if not initialized - because onCreate is called on screen rotation. 73 | if (!initDone) copyBinaryFile(); 74 | 75 | setContentView(R.layout.activity_main); 76 | 77 | // Create the adapter that will return a fragment for each of the three primary sections of the activity. 78 | mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); 79 | 80 | // Set up the ViewPager with the sections adapter. 81 | mViewPager = (ViewPager) findViewById(R.id.container); 82 | mViewPager.setAdapter(mSectionsPagerAdapter); 83 | 84 | // Create the background synchronization thread 85 | if (synchronizeThread == null) { 86 | synchronizeThread = new SynchronizeThread(context); 87 | Thread t = new Thread(synchronizeThread); 88 | t.start(); 89 | } 90 | 91 | // Acquire wakelock 92 | PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 93 | wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "pocketnode:wakelock"); 94 | wakelock.acquire(); 95 | 96 | initDone = true; 97 | } 98 | 99 | @Override 100 | public boolean onCreateOptionsMenu(Menu menu) { 101 | getMenuInflater().inflate(R.menu.menu_main, menu); 102 | return true; 103 | } 104 | 105 | @Override 106 | public void onResume(){ 107 | super.onResume(); 108 | getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.newColorPrimary))); 109 | 110 | 111 | setTheme(MainActivity.getStyle(context)); 112 | } 113 | 114 | @Override 115 | public boolean onOptionsItemSelected(MenuItem item) { 116 | int id = item.getItemId(); 117 | 118 | if (id == R.id.action_settings) { 119 | // launch settings activity 120 | startActivity(new Intent(MainActivity.this, SettingsPrefActivity.class)); 121 | return true; 122 | } 123 | if (id == R.id.action_about) { 124 | // launch about activity 125 | startActivity(new Intent(MainActivity.this, AboutActivity.class)); 126 | return true; 127 | } 128 | 129 | return super.onOptionsItemSelected(item); 130 | } 131 | 132 | 133 | /** 134 | * Copy the aeond binary file to a location where wa have execute rights 135 | */ 136 | private void copyBinaryFile() { 137 | Resources res = getResources(); 138 | //Log.d(TAG, " " + is64bitsProcessor()); 139 | 140 | InputStream in_s = res.openRawResource(is64bitsProcessor() ? R.raw.monerod64 : R.raw.monerod32); 141 | try { 142 | // read wownerod binary file from the ressource raw folder 143 | byte[] b = new byte[in_s.available()]; 144 | in_s.read(b); 145 | String pathName = context.getApplicationInfo().dataDir + "/lib"; 146 | 147 | BINARY_PATH = context.getCacheDir().getPath() + "/../monerod"; 148 | 149 | // write the file to an android executable location 150 | OutputStream outputStream = new FileOutputStream(BINARY_PATH); 151 | outputStream.write(b); 152 | outputStream.flush(); 153 | outputStream.close(); 154 | 155 | // make the file executable 156 | File f = new File(BINARY_PATH); 157 | f.setExecutable(true); 158 | 159 | } catch (IOException e) { 160 | Log.e(TAG, e.getMessage()); 161 | AlertDialog.Builder builder; 162 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 163 | builder = new AlertDialog.Builder(MainActivity.this, android.R.style.Theme_Material_Dialog_Alert); 164 | } else { 165 | builder = new AlertDialog.Builder(MainActivity.this); 166 | } 167 | builder.setTitle("Copy binary file") 168 | .setMessage(e.getMessage()) 169 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 170 | public void onClick(DialogInterface dialog, int which) { 171 | } 172 | }) 173 | .setIcon(android.R.drawable.ic_dialog_alert) 174 | .show(); 175 | 176 | } 177 | } 178 | 179 | 180 | public static void setAboutActivity(AppCompatPreferenceActivity _aboutActivity) { 181 | aboutActivity = _aboutActivity; 182 | } 183 | 184 | private boolean is64bitsProcessor() { 185 | String supported[] = Build.SUPPORTED_ABIS; 186 | for (String s : supported) { 187 | if (s.equals("arm64-v8a")) return true; 188 | } 189 | return false; 190 | } 191 | 192 | /** 193 | * A {@link FragmentPagerAdapter} that returns a fragment corresponding to 194 | * one of the sections/tabs/pages. 195 | */ 196 | public class SectionsPagerAdapter extends FragmentPagerAdapter { 197 | 198 | public SectionsPagerAdapter(FragmentManager fm) { 199 | super(fm); 200 | } 201 | 202 | @Override 203 | public android.support.v4.app.Fragment getItem(int position) { 204 | // getItem is called to instantiate the fragment for the given page. 205 | if (position == FRAGMENT_MAIN) return new MainSlideFragment(); 206 | else if (position == FRAGMENT_LOG) return new LogSlideFragment(); 207 | else return null; 208 | } 209 | 210 | @Override 211 | public int getCount() { 212 | return 2; 213 | } 214 | } 215 | 216 | public static ViewPager getmViewPager() { 217 | return mViewPager; 218 | } 219 | 220 | public static void setThemeActivity(AppCompatPreferenceActivity themeActivity) { 221 | MainActivity.themeActivity = themeActivity; 222 | } 223 | 224 | public static int getStyle(Context context) { 225 | return R.style.AppTheme; 226 | } 227 | 228 | 229 | public static Context getContext() { 230 | return context; 231 | } 232 | 233 | @Override 234 | protected void onDestroy() { 235 | // Clear wakelock 236 | wakelock.release(); 237 | super.onDestroy(); 238 | } 239 | 240 | } -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/SettingsPrefActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app; 17 | 18 | import android.Manifest; 19 | import android.app.Activity; 20 | import android.app.AlertDialog; 21 | import android.content.Context; 22 | import android.content.DialogInterface; 23 | import android.content.SharedPreferences; 24 | import android.content.pm.PackageManager; 25 | import android.graphics.Color; 26 | import android.graphics.drawable.ColorDrawable; 27 | import android.os.Build; 28 | import android.os.Bundle; 29 | import android.preference.PreferenceFragment; 30 | import android.preference.PreferenceManager; 31 | import android.support.v4.app.ActivityCompat; 32 | import android.support.v4.content.ContextCompat; 33 | import android.util.Log; 34 | import android.view.MenuItem; 35 | 36 | import org.aeon.aeondaemon.app.Fragments.MainSlideFragment; 37 | import org.aeon.aeondaemon.app.model.CollectPreferences; 38 | import org.aeon.aeondaemon.app.model.Launcher; 39 | import org.aeon.aeondaemon.app.model.SynchronizeThread; 40 | 41 | import java.io.File; 42 | 43 | public class SettingsPrefActivity extends AppCompatPreferenceActivity { 44 | private static final String TAG = SettingsPrefActivity.class.getSimpleName(); 45 | private SharedPreferences.OnSharedPreferenceChangeListener listener; 46 | private Context context = null; 47 | private Activity activity = null; 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | 53 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 54 | context = getApplicationContext(); 55 | activity = this; 56 | 57 | 58 | // load settings fragment 59 | setContentView(R.layout.activity_settings); 60 | getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit(); 61 | 62 | listener = new SharedPreferences.OnSharedPreferenceChangeListener() { 63 | @Override 64 | public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 65 | Launcher launcher = SynchronizeThread.getLauncher(); 66 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); 67 | 68 | // If SD card enabled set a preference if empty 69 | String path = preferences.getString("sd_storage", ""); 70 | boolean useSD = preferences.getBoolean("use_sd_card", false); 71 | // Card has been inserted and "Use SD card" checked 72 | if (useSD && path.equals("")) { 73 | SharedPreferences.Editor editor = preferences.edit(); 74 | if (CollectPreferences.getExternalStoragePath(context) != null) 75 | editor.putString("sd_storage", CollectPreferences.getExternalStoragePath(context)); 76 | else 77 | editor.putBoolean("use_sd_card", false); 78 | editor.commit(); 79 | 80 | getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit(); 81 | 82 | } 83 | 84 | // If custom location set a preference if empty 85 | path = preferences.getString("sd_custom_storage", ""); 86 | boolean useCustom = preferences.getBoolean("use_custom_storage", false); 87 | // Card has been inserted and "Use SD card" checked 88 | if (useCustom && path.equals("")) { 89 | 90 | SharedPreferences.Editor editor = preferences.edit(); 91 | editor.putString("sd_custom_storage", CollectPreferences.getCustomPath()); 92 | editor.commit(); 93 | 94 | getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit(); 95 | 96 | } 97 | 98 | // Android 6+ 99 | if (useCustom || useSD ) { 100 | boolean hasPermission = (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED); 101 | if (!hasPermission) { 102 | ActivityCompat.requestPermissions(activity, 103 | new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 104 | 1); 105 | } 106 | } 107 | 108 | if (useSD && useCustom) { 109 | AlertDialog.Builder builder; 110 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 111 | builder = new AlertDialog.Builder(SettingsPrefActivity.this, android.R.style.Theme_Material_Dialog_Alert); 112 | } else { 113 | builder = new AlertDialog.Builder(SettingsPrefActivity.this); 114 | } 115 | builder.setTitle(R.string.sd_custom_error) 116 | .setMessage(R.string.sd_custom_error_msg) 117 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { 118 | public void onClick(DialogInterface dialog, int which) { 119 | } 120 | }) 121 | .setIcon(android.R.drawable.ic_dialog_alert) 122 | .show(); 123 | 124 | SharedPreferences.Editor editor = preferences.edit(); 125 | editor.putBoolean("use_custom_storage", false); 126 | editor.commit(); 127 | 128 | getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit(); 129 | } 130 | MainSlideFragment.setHasCriticalError(false); 131 | if (launcher != null) { 132 | Log.e(TAG, "Stop Wownero daemon"); 133 | launcher.exit(); 134 | } 135 | } 136 | }; 137 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); 138 | preferences.registerOnSharedPreferenceChangeListener(listener); 139 | 140 | String sdLocation = CollectPreferences.getExternalStoragePath(context); 141 | // if the SD card has been removed. 142 | if (sdLocation == null) { 143 | SharedPreferences.Editor editor = preferences.edit(); 144 | editor.putBoolean("use_sd_card", false); 145 | editor.commit(); 146 | } 147 | setTheme(MainActivity.getStyle(getApplicationContext())); 148 | 149 | // TODO: Remove/check this 150 | getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE)); 151 | } 152 | 153 | public static class MainPreferenceFragment extends PreferenceFragment { 154 | @Override 155 | public void onCreate(final Bundle savedInstanceState) { 156 | super.onCreate(savedInstanceState); 157 | addPreferencesFromResource(R.xml.pref_settings); 158 | } 159 | } 160 | 161 | @Override 162 | public boolean onOptionsItemSelected(MenuItem item) { 163 | if (item.getItemId() == android.R.id.home) { 164 | onBackPressed(); 165 | } 166 | return super.onOptionsItemSelected(item); 167 | } 168 | 169 | @Override 170 | public void onResume() { 171 | super.onResume(); 172 | 173 | setTheme(R.style.AppTheme); 174 | } 175 | 176 | } -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/ThemeActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app; 17 | 18 | import android.content.Context; 19 | import android.content.SharedPreferences; 20 | import android.graphics.drawable.ColorDrawable; 21 | import android.os.Bundle; 22 | import android.preference.PreferenceFragment; 23 | import android.support.v4.content.ContextCompat; 24 | import android.support.v7.app.ActionBar; 25 | import android.util.Log; 26 | import android.view.MenuItem; 27 | 28 | public class ThemeActivity extends AppCompatPreferenceActivity { 29 | private static final String TAG = ThemeActivity.class.getSimpleName(); 30 | private Context context = null; 31 | private SharedPreferences.OnSharedPreferenceChangeListener listener; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | context = getApplicationContext(); 37 | 38 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 39 | 40 | // load settings fragment 41 | getFragmentManager().beginTransaction().replace(android.R.id.content, new ThemeActivity.MainPreferenceFragment()).commit(); 42 | 43 | setContentView(R.layout.activity_theme); 44 | MainActivity.setThemeActivity(this); 45 | setTheme(MainActivity.getStyle(context)); 46 | } 47 | 48 | @Override 49 | public boolean onOptionsItemSelected(MenuItem item) { 50 | if (item.getItemId() == android.R.id.home) { 51 | onBackPressed(); 52 | } 53 | return super.onOptionsItemSelected(item); 54 | } 55 | 56 | public static class MainPreferenceFragment extends PreferenceFragment { 57 | @Override 58 | public void onCreate(final Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | addPreferencesFromResource(R.xml.pref_theme); 61 | } 62 | } 63 | 64 | @Override 65 | public void onResume(){ 66 | super.onResume(); 67 | setTheme(MainActivity.getStyle(context)); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/model/CollectPreferences.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app.model; 17 | 18 | import static android.os.Environment.getExternalStoragePublicDirectory; 19 | 20 | import android.content.Context; 21 | import android.content.SharedPreferences; 22 | import android.os.Build; 23 | import android.os.Environment; 24 | import android.support.v4.content.ContextCompat; 25 | import android.util.Log; 26 | 27 | import java.io.File; 28 | import java.io.FileNotFoundException; 29 | import java.io.FileOutputStream; 30 | import java.util.Map; 31 | 32 | public class CollectPreferences { 33 | public static Settings collectedPreferences = new Settings(); 34 | private static final String TAG = CollectPreferences.class.getSimpleName(); 35 | 36 | public static void collect(SharedPreferences prefs) { 37 | Map keys = prefs.getAll(); 38 | for (Map.Entry entry : keys.entrySet()) { 39 | if (entry.getKey().equals("Testnet")) { 40 | Boolean t = prefs.getBoolean("Testnet", false); 41 | collectedPreferences.setIsTestnet(t.booleanValue()); 42 | } 43 | if (entry.getKey().equals("Stagenet")) { 44 | Boolean t = prefs.getBoolean("Stagenet", false); 45 | collectedPreferences.setIsStageNet(t.booleanValue()); 46 | } 47 | if (entry.getKey().equals("p2pBindPort")) { 48 | String t = prefs.getString("p2pBindPort", ""); 49 | if (!t.equals("")) collectedPreferences.setP2pBindPort(Integer.parseInt(t)); 50 | else collectedPreferences.setP2pBindPort(0); 51 | } 52 | if (entry.getKey().equals("rpcBindPort")) { 53 | String t = prefs.getString("rpcBindPort", ""); 54 | if (!t.equals("")) collectedPreferences.setRpcBindPort(Integer.parseInt(t)); 55 | else collectedPreferences.setRpcBindPort(0); 56 | } 57 | if (entry.getKey().equals("zmqBindPort")) { 58 | String t = prefs.getString("zmqBindPort", ""); 59 | if (!t.equals("")) collectedPreferences.setZmqRpcPort(Integer.parseInt(t)); 60 | else collectedPreferences.setZmqRpcPort(0); 61 | } 62 | if (entry.getKey().equals("blockSyncSize")) { 63 | String t = prefs.getString("blockSyncSize", ""); 64 | if (!t.equals("")) collectedPreferences.setBlockSyncSize(Integer.parseInt(t)); 65 | else collectedPreferences.setBlockSyncSize(0); 66 | } 67 | if (entry.getKey().equals("limitRate")) { 68 | String t = prefs.getString("limitRate", ""); 69 | if (!t.equals("")) collectedPreferences.setLimitRate(Integer.parseInt(t)); 70 | else collectedPreferences.setLimitRate(-1); 71 | } 72 | if (entry.getKey().equals("limitRateDown")) { 73 | String t = prefs.getString("limitRateDown", ""); 74 | if (!t.equals("")) collectedPreferences.setLimitRateDown(Integer.parseInt(t)); 75 | else collectedPreferences.setLimitRateDown(-1); 76 | } 77 | if (entry.getKey().equals("limitRateUp")) { 78 | String t = prefs.getString("limitRateUp", ""); 79 | if (!t.equals("")) collectedPreferences.setLimitRateUp(Integer.parseInt(t)); 80 | else collectedPreferences.setLimitRateUp(-1); 81 | } 82 | if (entry.getKey().equals("outPeers")) { 83 | String t = prefs.getString("outPeers", ""); 84 | if (!t.equals("")) collectedPreferences.setOutPeers(Integer.parseInt(t)); 85 | else collectedPreferences.setOutPeers(-1); 86 | } 87 | if (entry.getKey().equals("inPeers")) { 88 | String t = prefs.getString("inPeers", ""); 89 | if (!t.equals("")) collectedPreferences.setInPeers(Integer.parseInt(t)); 90 | else collectedPreferences.setInPeers(-1); 91 | } 92 | if (entry.getKey().equals("peerNode")) { 93 | String t = prefs.getString("peerNode", ""); 94 | if (!t.equals("")) collectedPreferences.setPeerNode(t); 95 | else collectedPreferences.setPeerNode(null); 96 | } 97 | if (entry.getKey().equals("exclusiveNode")) { 98 | String t = prefs.getString("exclusiveNode", ""); 99 | if (!t.equals("")) collectedPreferences.setAddExclusiveNode(t); 100 | else collectedPreferences.setAddExclusiveNode(null); 101 | } 102 | if (entry.getKey().equals("priorityNode")) { 103 | String t = prefs.getString("priorityNode", ""); 104 | if (!t.equals("")) collectedPreferences.setAddPriorityNode(t); 105 | else collectedPreferences.setAddPriorityNode(null); 106 | } 107 | if (entry.getKey().equals("restricted_rpc")) { 108 | Boolean t = prefs.getBoolean("restricted_rpc", true); 109 | collectedPreferences.setRestrictedRpc(t.booleanValue()); 110 | } 111 | if (entry.getKey().equals("use_sd_card")) { 112 | Boolean t = prefs.getBoolean("use_sd_card", false); 113 | collectedPreferences.setUseSDCard(t.booleanValue()); 114 | } 115 | if (entry.getKey().equals("sd_storage")) { 116 | String t = prefs.getString("sd_storage", ""); 117 | if (!t.equals("")) collectedPreferences.setSdCardPath(t); 118 | else collectedPreferences.setSdCardPath(null); 119 | } 120 | if (entry.getKey().equals("use_custom_storage")) { 121 | Boolean t = prefs.getBoolean("use_custom_storage", false); 122 | collectedPreferences.setUseCustomStorage(t.booleanValue()); 123 | } 124 | if (entry.getKey().equals("sd_custom_storage")) { 125 | String t = prefs.getString("sd_custom_storage", ""); 126 | if (!t.equals("")) collectedPreferences.setCustomStoragePath(t); 127 | else collectedPreferences.setCustomStoragePath(null); 128 | } 129 | if (entry.getKey().equals("loglevel")) { 130 | Integer t = Integer.parseInt(prefs.getString("loglevel", "0")); 131 | collectedPreferences.setLogLevel(t.intValue()); 132 | } 133 | if (entry.getKey().equals("enable_node")) { 134 | Boolean t = prefs.getBoolean("enable_node", false); 135 | collectedPreferences.setEnableNode(t.booleanValue()); 136 | } 137 | if (entry.getKey().equals("fast_bloc_sync")) { 138 | Boolean t = prefs.getBoolean("fast_bloc_sync", false); 139 | collectedPreferences.setFastBlocSync(t.booleanValue()); 140 | } 141 | if (entry.getKey().equals("pruning")) { 142 | Boolean t = prefs.getBoolean("pruning", true); 143 | collectedPreferences.setUsePruning(t.booleanValue()); 144 | } 145 | 146 | } 147 | } 148 | 149 | public static String getExternalStoragePath(Context context) { 150 | File[] externalStorageVolumes = ContextCompat.getExternalFilesDirs(context, null); 151 | 152 | /** 153 | * FIXME: Hacky solution here, but it's the best one I've found so far. If the string 154 | * replacement is removed, it writes to a private directory on the SD card. 155 | * I'd like to keep the directory publicly accessible in case 156 | * wants to manually sideload their own data. For a fix, I'd prefer to use some kind of 157 | * existing Android API (surely there's something better than this) that targets the Documents 158 | * directory in the SDCard folder. 159 | */ 160 | if (externalStorageVolumes.length > 1) { 161 | // TODO: Add check for usable space 162 | 163 | File primaryExternalStorage = externalStorageVolumes[1]; 164 | String appName = context.getApplicationInfo().packageName; 165 | 166 | return (primaryExternalStorage + "").replace("/Android/data/" + appName + "/files", "/Documents/bitmonero"); 167 | } else { 168 | // No external storage available 169 | return null; 170 | } 171 | } 172 | 173 | public static String getCustomPath() { 174 | File file = new File(Environment.getExternalStorageDirectory(), "wownero"); 175 | if (!file.mkdirs()) { 176 | Log.e(TAG, "Directory not created"); 177 | } 178 | return file.getAbsolutePath(); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/model/Launcher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.aeon.aeondaemon.app.model; 18 | 19 | import android.util.Log; 20 | 21 | import org.aeon.aeondaemon.app.Fragments.MainSlideFragment; 22 | import org.aeon.aeondaemon.app.MainActivity; 23 | 24 | import java.io.BufferedReader; 25 | import java.io.BufferedWriter; 26 | import java.io.File; 27 | import java.io.IOException; 28 | import java.io.InputStreamReader; 29 | import java.io.OutputStreamWriter; 30 | import java.lang.reflect.Field; 31 | import java.util.ArrayList; 32 | import java.util.Map; 33 | 34 | public class Launcher { 35 | private static final String TAG = Launcher.class.getSimpleName(); 36 | private static int MAX_LOG_SIZE = 30000; 37 | private enum ProcessState { STOPPED, STARTING, RUNNING, STOPPING }; 38 | 39 | private BufferedReader reader=null; 40 | private BufferedWriter writer=null; 41 | private String version=null; 42 | private StringBuffer logs=null; 43 | private String height; 44 | private String target; 45 | private String syncPercentage; 46 | private String peers; 47 | private String downloading; 48 | private Process process=null; 49 | private ProcessState processState = ProcessState.STOPPED; 50 | 51 | public String start(Settings pref) { 52 | if (!checkSDCard(pref)) { 53 | return "Fail to create "+pref.getSdCardPath(); 54 | } 55 | MainSlideFragment.setHasCriticalError(false); 56 | try { 57 | // reset log buffer 58 | if (logs != null) logs.delete(0,logs.length()); 59 | 60 | File f = new File(MainActivity.BINARY_PATH); 61 | 62 | String env = getEnv(pref); 63 | Log.e(TAG , env); 64 | 65 | // Executes the command. 66 | process = Runtime.getRuntime().exec(MainActivity.BINARY_PATH+" "+env); 67 | 68 | try { 69 | Field field = process.getClass().getDeclaredField("pid"); 70 | field.setAccessible(true); 71 | } catch (Throwable e) { 72 | Log.e(TAG,e.getMessage()); 73 | } 74 | 75 | // maps stdout 76 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 77 | 78 | // maps stdin 79 | writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); 80 | 81 | } catch (IOException e) { 82 | Log.e(TAG,e.getMessage()); 83 | return e.getMessage(); 84 | } 85 | processState = ProcessState.STARTING; 86 | 87 | return null; 88 | } 89 | 90 | /** 91 | * Collect the logs, get the version string and get current sync status 92 | * 93 | * Non blocking I/O 94 | */ 95 | public void updateStatus() { 96 | try { 97 | //Log.d(TAG,"updateStatus "+reader.ready()); 98 | if (reader != null && reader.ready()) { 99 | char[] buffer = new char[16384]; 100 | if (logs == null) logs = new StringBuffer(); 101 | 102 | while (reader.ready()) { 103 | int read = reader.read(buffer); 104 | if (read > 0) { 105 | logs.append(buffer, 0, read); 106 | } 107 | } 108 | 109 | // truncate if log too big 110 | if (logs.length() > MAX_LOG_SIZE) 111 | logs.delete(0,logs.length() - MAX_LOG_SIZE); 112 | 113 | // Try to get monerod version and build number 114 | if (version == null) { 115 | int i = 0; //logs.toString().indexOf("I Wownero"); 116 | //if (i != -1) { 117 | int j = logs.toString().substring(i).indexOf("Monero '"); 118 | if (j != -1) { 119 | int k = logs.toString().substring(i+j).indexOf(")"); 120 | version = logs.toString().substring(i+j,i+j+k+1); 121 | } 122 | //} 123 | } 124 | 125 | // Get Sync Percentage 126 | int s = logs.toString().lastIndexOf("%,"); 127 | if (s > 0) { 128 | String syncReversed = ""; 129 | s--; 130 | while (logs.charAt(s) != '(') { 131 | syncReversed += logs.charAt(s); 132 | s--; 133 | } 134 | syncPercentage = new StringBuilder(syncReversed).reverse().toString(); 135 | } 136 | 137 | // Update Height and target 138 | int i = logs.toString().lastIndexOf("Height:"); 139 | if (i > 0) { 140 | height = ""; 141 | target = ""; 142 | while (logs.charAt(i) != ' ') i++; 143 | while (logs.charAt(i) != ',') { 144 | height += logs.charAt(i); 145 | i++; 146 | } 147 | i += 2; 148 | while (logs.charAt(i) != ' ') i++; 149 | i++; 150 | while (logs.charAt(i) != ' ') { 151 | target += logs.charAt(i); 152 | i++; 153 | } 154 | } 155 | 156 | // Download speed 157 | i = logs.toString().lastIndexOf("Downloading at "); 158 | if (i > 0) { 159 | downloading = ""; 160 | i += 15; 161 | while (logs.charAt(i) != ' ') { 162 | downloading += logs.charAt(i); 163 | i++; 164 | } 165 | i++; 166 | } 167 | 168 | // Number of peers 169 | i = logs.toString().lastIndexOf(" peers\n"); 170 | if (i > 0) { 171 | i --; 172 | peers = ""; 173 | while (logs.charAt(i) >= '0' && logs.charAt(i) <= '9') i--; 174 | i++; 175 | while (logs.charAt(i) != ' ') { 176 | peers += logs.charAt(i); 177 | i++; 178 | } 179 | } 180 | } 181 | 182 | } catch (IOException e) { 183 | Log.e(TAG,e.getMessage()); 184 | } 185 | } 186 | 187 | public void getSyncInfo() { 188 | try { 189 | // if process not already terminated 190 | if (writer != null) { 191 | writer.write("sync_info\n"); 192 | writer.flush(); 193 | } 194 | } catch (IOException e) { 195 | Log.e(TAG,"getSyncInfo: " +e.getMessage()); 196 | } 197 | } 198 | 199 | public void exit() { 200 | // sending an exit twice might make it waiting forever 201 | if (processState == ProcessState.STOPPING) 202 | return; 203 | 204 | try { 205 | if (writer != null) { 206 | writer.write("exit\n"); 207 | writer.flush(); 208 | } 209 | } catch (IOException e) { 210 | Log.e(TAG,e.getMessage()); 211 | } 212 | processState = ProcessState.STOPPING; 213 | } 214 | 215 | public String getEnv(Settings pref) { 216 | ArrayList a = new ArrayList(); 217 | 218 | a.add("--data-dir "+pref.getDataDir()); 219 | if (pref.getLogFile() != null) a.add("--log-file "+pref.getLogFile()); 220 | if (pref.getLogLevel() > 0) a.add("--log-level "+pref.getLogLevel()); 221 | if (pref.getIsTestnet()) a.add("--testnet"); 222 | if (pref.getIsStageNet()) a.add("--stagenet"); 223 | if (pref.getBlockSyncSize() != 0) a.add("--block-sync-size "+pref.getBlockSyncSize()); 224 | if (pref.getZmqRpcPort() != 0) a.add("--zmq-rpc-bind-port "+pref.getZmqRpcPort()); 225 | if (pref.getP2pBindPort() != 0) a.add("--p2p-bind-port "+pref.getP2pBindPort()); 226 | if (pref.getRpcBindPort() != 0) a.add("--rpc-bind-port "+pref.getRpcBindPort()); 227 | if (pref.getAddExclusiveNode() != null) a.add("--add-exclusive-node "+pref.getAddExclusiveNode()); 228 | if (pref.getSeedNode() != null) a.add("--seed-node "+pref.getSeedNode()); 229 | if (pref.getOutPeers() != -1) a.add("--out-peers "+pref.getOutPeers()); 230 | if (pref.getInPeers() != -1) a.add("--in-peers "+pref.getInPeers()); 231 | if (pref.getLimitRateUp() != -1) a.add("--limit-rate-up "+pref.getLimitRateUp()); 232 | if (pref.getLimitRateDown() != -1) a.add("--limit-rate-down "+pref.getLimitRateDown()); 233 | if (pref.getLimitRate() != -1) a.add("--limit-rate "+pref.getLimitRate()); 234 | if (pref.getBoostrapDaemonAdress() != null) a.add("--bootstrap-daemon-address "+pref.getBoostrapDaemonAdress()); 235 | if (pref.getBoostrapDaemonLogin() != null) a.add("--bootstrap-daemon-login "+pref.getBoostrapDaemonLogin()); 236 | if (pref.getPeerNode() != null) a.add("--add-peer "+pref.getPeerNode()); 237 | if (pref.getAddPriorityNode() != null) a.add("--add-priority-node "+pref.getAddPriorityNode()); 238 | if (pref.getRestrictedRpc()) a.add("--restricted-rpc "); 239 | if (pref.isFastBlocSync()) a.add("--fast-block-sync 1 "); 240 | if (pref.usePruning()) a.add("--prune-blockchain "); 241 | 242 | String ret = ""; 243 | for (String s : a) { 244 | ret += s + " "; 245 | } 246 | 247 | ret += "--db-sync-mode fast:async:1000000 "; 248 | return ret; 249 | } 250 | 251 | public String getPeers() { 252 | return peers; 253 | } 254 | 255 | public String getHeight() { 256 | return height; 257 | } 258 | 259 | public String getTarget() { 260 | return target; 261 | } 262 | 263 | public String getSyncPercentage() { return syncPercentage; } 264 | 265 | public String getVersion() { 266 | return version; 267 | } 268 | 269 | public String getLogs() { 270 | return logs == null ? "" : logs.toString(); 271 | } 272 | 273 | public boolean isStopped() { 274 | return processState == ProcessState.STOPPED; 275 | } 276 | public boolean isStarting() { return processState == ProcessState.STARTING; } 277 | 278 | public String getDownloading() { 279 | return downloading; 280 | } 281 | 282 | public boolean isAlive() { 283 | try { 284 | ProcessBuilder builder = new ProcessBuilder("ps"); // | /system/bin/grep aeond"); 285 | builder.redirectErrorStream(true); 286 | Map env = builder.environment(); 287 | env.put("PATH","/bin:/system/bin"); 288 | Process process = builder.start(); 289 | 290 | InputStreamReader isReader = new InputStreamReader(process.getInputStream()); 291 | BufferedReader bReader = new BufferedReader(isReader); 292 | String strLine = null; 293 | while ((strLine = bReader.readLine()) != null) { 294 | int i = strLine.lastIndexOf("monerod"); 295 | if (i > 0 && !(strLine.length() > i+8 && strLine.charAt(i+8) == 'a')) { 296 | processState = ProcessState.RUNNING; 297 | return true; 298 | } 299 | } 300 | } catch (Exception ex) { 301 | Log.e(TAG,"Got exception using getting the PID"+ ex.getMessage()); 302 | } 303 | processState = ProcessState.STOPPED; 304 | return false; 305 | } 306 | 307 | /** 308 | * If the SD card is in use, try to create the folder. 309 | * @param pref 310 | * @return 311 | */ 312 | private boolean checkSDCard(Settings pref) { 313 | if (pref.isUseSDCard() && pref.getSdCardPath() != null) { 314 | // Try to create location 315 | File file = new File(pref.getSdCardPath()); 316 | boolean r = file.exists(); 317 | if (!r) r = file.mkdir(); 318 | //Log.d(TAG, "Check SD card " + file.exists() + " Writable " + " r=" + r + " " + file.canWrite() + " " + file.getAbsolutePath()); 319 | return r; 320 | } else if (pref.isUseCustomStorage() && pref.getCustomStoragePath() != null) { 321 | // Try to create location 322 | File file = new File(pref.getCustomStoragePath()); 323 | boolean r = file.exists(); 324 | if (!r) r = file.mkdir(); 325 | //Log.d(TAG, "Check SD card " + file.exists() + " Writable " + " r=" + r + " " + file.canWrite() + " " + file.getAbsolutePath()); 326 | return r; 327 | } else 328 | return true; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/model/Settings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app.model; 17 | 18 | public class Settings { 19 | private boolean enableNode =false; 20 | private String dataDir=null; 21 | private String logFile="/dev/null"; 22 | private int logLevel=0; 23 | private Boolean isTestnet = false; 24 | private Boolean isStageNet = false; 25 | private int blockSyncSize = 0; 26 | private int zmqRpcPort=0; 27 | private int p2pBindPort=0; 28 | private int rpcBindPort=0; 29 | private String addExclusiveNode=null; 30 | private String addPriorityNode=null; 31 | private String adress="Wmsmmjtzk269mpmWm9CTC8DXDs9FZmKdrbFqm1gAmdFxJwEtsZU9PxDJDLYxtLsoSSjn6y6iXYcXVfgYSAGC5vrL13rDqUs4n"; 32 | private String seedNode=null; 33 | private String peerNode=null; 34 | private int outPeers=-1; 35 | private int inPeers=-1; 36 | private int limitRateUp=-1; 37 | private int limitRateDown=-1; 38 | private int limitRate=-1; 39 | private String boostrapDaemonAdress=null; 40 | private String boostrapDaemonLogin=null; 41 | private Boolean restrictedRpc=true; 42 | private String sdCardPath=null; 43 | private boolean useSDCard=false; 44 | private String customStoragePath=null; 45 | private boolean useCustomStorage=false; 46 | private boolean fastBlocSync=false; 47 | 48 | private boolean usePruning=true; 49 | 50 | public boolean isUseSDCard() { 51 | return useSDCard; 52 | } 53 | 54 | public void setUseSDCard(boolean useSDCard) { 55 | this.useSDCard = useSDCard; 56 | } 57 | 58 | public void setSdCardPath(String sdCardPath) { 59 | this.sdCardPath = sdCardPath; 60 | } 61 | 62 | public void setTestnet(Boolean testnet) { 63 | isTestnet = testnet; 64 | } 65 | 66 | public void setStageNet(Boolean stageNet) { 67 | isStageNet = stageNet; 68 | } 69 | 70 | 71 | public String getSdCardPath() { 72 | return sdCardPath; 73 | } 74 | 75 | public String getDataDir() { 76 | return dataDir; 77 | } 78 | public void setDataDir(String dataDir) { 79 | this.dataDir = dataDir; 80 | } 81 | public String getLogFile() { 82 | return logFile; 83 | } 84 | public void setLogFile(String logFile) { 85 | this.logFile = logFile; 86 | } 87 | public Boolean getIsTestnet() { 88 | return isTestnet; 89 | } 90 | public void setIsTestnet(Boolean isTestnet) { 91 | this.isTestnet = isTestnet; 92 | } 93 | public Boolean getIsStageNet() { 94 | return isStageNet; 95 | } 96 | public void setIsStageNet(Boolean isStageNet) { 97 | this.isStageNet = isStageNet; 98 | } 99 | public int getBlockSyncSize() { 100 | return blockSyncSize; 101 | } 102 | public void setBlockSyncSize(int blockSyncSize) { 103 | this.blockSyncSize = blockSyncSize; 104 | } 105 | public int getZmqRpcPort() { 106 | return zmqRpcPort; 107 | } 108 | public void setZmqRpcPort(int zmqRpcPort) { 109 | this.zmqRpcPort = zmqRpcPort; 110 | } 111 | public int getP2pBindPort() { 112 | return p2pBindPort; 113 | } 114 | public void setP2pBindPort(int p2pBindPort) { 115 | this.p2pBindPort = p2pBindPort; 116 | } 117 | public int getRpcBindPort() { 118 | return rpcBindPort; 119 | } 120 | public void setRpcBindPort(int rpcBindPort) { 121 | this.rpcBindPort = rpcBindPort; 122 | } 123 | public String getAddExclusiveNode() { 124 | return addExclusiveNode; 125 | } 126 | public void setAddExclusiveNode(String addExclusiveNode) { 127 | this.addExclusiveNode = addExclusiveNode; 128 | } 129 | public String getAdress() { 130 | return adress; 131 | } 132 | public void setAdress(String adress) { 133 | this.adress = adress; 134 | } 135 | public String getSeedNode() { 136 | return seedNode; 137 | } 138 | public void setSeedNode(String seedNode) { 139 | this.seedNode = seedNode; 140 | } 141 | public int getOutPeers() { 142 | return outPeers; 143 | } 144 | public void setOutPeers(int outPeers) { 145 | this.outPeers = outPeers; 146 | } 147 | public int getInPeers() { 148 | return inPeers; 149 | } 150 | public void setInPeers(int inPeers) { 151 | this.inPeers = inPeers; 152 | } 153 | public int getLimitRateUp() { 154 | return limitRateUp; 155 | } 156 | public void setLimitRateUp(int limitRateUp) { 157 | this.limitRateUp = limitRateUp; 158 | } 159 | public int getLimitRateDown() { 160 | return limitRateDown; 161 | } 162 | public void setLimitRateDown(int limitRateDown) { 163 | this.limitRateDown = limitRateDown; 164 | } 165 | public int getLimitRate() { 166 | return limitRate; 167 | } 168 | public void setLimitRate(int limitRate) { 169 | this.limitRate = limitRate; 170 | } 171 | public String getBoostrapDaemonAdress() { 172 | return boostrapDaemonAdress; 173 | } 174 | public void setBoostrapDaemonAdress(String boostrapDaemonAdress) { 175 | this.boostrapDaemonAdress = boostrapDaemonAdress; 176 | } 177 | public String getBoostrapDaemonLogin() { 178 | return boostrapDaemonLogin; 179 | } 180 | public void setBoostrapDaemonLogin(String boostrapDaemonLogin) { 181 | this.boostrapDaemonLogin = boostrapDaemonLogin; 182 | } 183 | public String getPeerNode() { 184 | return peerNode; 185 | } 186 | public void setPeerNode(String peerNode) { 187 | this.peerNode = peerNode; 188 | } 189 | public String getAddPriorityNode() { 190 | return addPriorityNode; 191 | } 192 | public void setAddPriorityNode(String addPriorityNode) { 193 | this.addPriorityNode = addPriorityNode; 194 | } 195 | public Boolean getRestrictedRpc() { 196 | return restrictedRpc; 197 | } 198 | public void setRestrictedRpc(Boolean restrictedRpc) { 199 | this.restrictedRpc = restrictedRpc; 200 | } 201 | 202 | public int getLogLevel() { 203 | return logLevel; 204 | } 205 | 206 | public Boolean getTestnet() { 207 | return isTestnet; 208 | } 209 | 210 | public Boolean getStageNet() { 211 | return isStageNet; 212 | } 213 | 214 | public void setLogLevel(int logLevel) { 215 | this.logLevel = logLevel; 216 | } 217 | 218 | public boolean getIsEnableNode() { return enableNode; } 219 | 220 | public void setEnableNode(boolean enableNode) { this.enableNode = enableNode; } 221 | 222 | public boolean isFastBlocSync() { 223 | return fastBlocSync; 224 | } 225 | 226 | public void setFastBlocSync(boolean fastBlocSync) { 227 | this.fastBlocSync = fastBlocSync; 228 | } 229 | 230 | public String getCustomStoragePath() { 231 | return customStoragePath; 232 | } 233 | 234 | public void setCustomStoragePath(String customStoragePath) { 235 | this.customStoragePath = customStoragePath; 236 | } 237 | 238 | public boolean isUseCustomStorage() { 239 | return useCustomStorage; 240 | } 241 | 242 | public void setUseCustomStorage(boolean useCustomStorage) { 243 | this.useCustomStorage = useCustomStorage; 244 | } 245 | 246 | 247 | public boolean usePruning() { 248 | return usePruning; 249 | } 250 | 251 | public void setUsePruning(boolean usePruning) { 252 | this.usePruning = usePruning; 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /app/src/main/java/org/aeon/aeondaemon/app/model/SynchronizeThread.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 enerc 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.aeon.aeondaemon.app.model; 17 | 18 | import android.content.Context; 19 | import android.content.SharedPreferences; 20 | import android.preference.PreferenceManager; 21 | import android.util.Log; 22 | 23 | import org.aeon.aeondaemon.app.Fragments.MainSlideFragment; 24 | 25 | public class SynchronizeThread implements Runnable { 26 | private static final String TAG = SynchronizeThread.class.getSimpleName(); 27 | private static Launcher launcher = null; 28 | private Context context; 29 | private static long RefreshInterval = 1000; 30 | private int counter = 0; 31 | private static int SendSyncCmd = 10; 32 | 33 | public SynchronizeThread(Context _context) { 34 | this.context = _context; 35 | } 36 | 37 | @Override 38 | public void run() { 39 | while (true) { 40 | /** 41 | * TODO: Review the logic here- this is where all the magic happens. 42 | * 43 | * - We always want to keep track of UI preference changes 44 | * - If we enable the node from the UI, we want to start 45 | * - If we disable the node from the UI, we want to stop 46 | * 47 | * - If the node stops, we want to update the UI to reflect that there are no 48 | * peers/connections, that it's not syncing, etc. rather than display the last known vals 49 | * 50 | */ 51 | boolean nodeEnabled = CollectPreferences.collectedPreferences.getIsEnableNode(); 52 | 53 | if (launcher == null) { 54 | launcher = new Launcher(); 55 | updatePreferences(); 56 | } 57 | if (launcher.isStopped() && nodeEnabled) { 58 | // Restart the background process 59 | updatePreferences(); // properties may have been changed in the settings. 60 | String status = launcher.start(CollectPreferences.collectedPreferences); 61 | if (status != null) { 62 | launcher.updateStatus(); 63 | String msg = ""; 64 | if (launcher.getLogs().length() > 0) msg = launcher.getLogs(); 65 | else msg = "monerod process failed to start. err=" + status; 66 | MainSlideFragment.execError = msg; 67 | } 68 | } else if (!nodeEnabled) { 69 | if (!launcher.isStopped()) { 70 | launcher.exit(); 71 | } 72 | updatePreferences(); // properties may have been changed in the settings. 73 | launcher.updateStatus(); 74 | } else if (launcher.isAlive()) { 75 | if (counter >= SendSyncCmd) { 76 | launcher.getSyncInfo(); 77 | counter = 0; 78 | } 79 | launcher.updateStatus(); 80 | //Log.e(TAG,"launcher.getSyncInfo"); 81 | } 82 | 83 | try { 84 | Thread.sleep(RefreshInterval); 85 | } catch (InterruptedException e) { 86 | Log.e(TAG, e.getMessage()); 87 | } 88 | counter ++; 89 | } 90 | } 91 | 92 | private void updatePreferences() { 93 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 94 | CollectPreferences.collect(preferences); 95 | 96 | // If using internal storage, set the path for it. 97 | if (CollectPreferences.collectedPreferences.isUseSDCard()) { 98 | CollectPreferences.collectedPreferences.setDataDir(CollectPreferences.collectedPreferences.getSdCardPath()); 99 | } else if (CollectPreferences.collectedPreferences.isUseCustomStorage()) { 100 | CollectPreferences.collectedPreferences.setDataDir(CollectPreferences.collectedPreferences.getCustomStoragePath()); 101 | } else { 102 | String storagePath = context.getFilesDir().getPath(); 103 | CollectPreferences.collectedPreferences.setDataDir(storagePath); 104 | } 105 | } 106 | 107 | public static Launcher getLauncher() { 108 | return launcher; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/actionbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/actionbar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/background.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/coins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/coins.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/coinscolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/coinscolor.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/mic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/mic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/mythbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/mythbar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/mythology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/mythology.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/oval_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/oval_unselected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/solidcolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/solidcolor.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/w001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/w001.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/wcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/wcoin.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/wowario.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/wowario.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/wsolidcolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/drawable/wsolidcolor.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 22 | 31 | 32 | 33 | 47 | 48 | 64 | 65 | 81 | 82 | 98 | 99 | 116 | 117 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 22 | 26 | 27 | 28 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 22 | 32 | 33 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 22 | 32 | 33 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/log_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 20 | 21 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 29 | 30 | 42 | 43 | 44 | 57 | 58 | 70 | 71 | 86 | 87 | 103 | 104 | 117 | 118 | 133 | 134 | 150 | 151 | 163 | 164 | 179 | 180 | 192 | 193 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 |

5 | 6 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/wic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-hdpi/wic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/wic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-hdpi/wic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/wic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-mdpi/wic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/wic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-mdpi/wic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/wic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xhdpi/wic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/wic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xhdpi/wic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/wic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxhdpi/wic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/wic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxhdpi/wic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/wic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxxhdpi/wic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/wic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/mipmap-xxxhdpi/wic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/monerod32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/raw/monerod32 -------------------------------------------------------------------------------- /app/src/main/res/raw/monerod64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/app/src/main/res/raw/monerod64 -------------------------------------------------------------------------------- /app/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Nœud crypto-monnaie Wownero 4 | Paramètres 5 | Paramètres 6 | A propos 7 | A propos 8 | Environnement de test 9 | Exécuter sur l\'environnement de test 10 | Environnement de test 11 | Environnement de validation 12 | Exécuter sur l\'environnement de validation 13 | Environnement de validation 14 | Port p2p 15 | Laisser vide pour le port par défaut 16 | Port d\'écoute p2p 17 | Port RPC 18 | Laisser vide pour le port par défaut 19 | Port RPC 20 | Port ZMQ 21 | Laisser vide pour localhost (127.0.0.1) 22 | Adresse du serveur ZMQ 23 | Limite de débit 24 | Configurer le débit maximal en kB/s 25 | Limite de débit 26 | Limite de débit descendant 27 | Configurer le débit maximal en kB/s 28 | Limite de débit descendant 29 | Configurer le débit maximal en kB/s 30 | Limite de débit montant 31 | Limite de débit montant 32 | Nombre de connexions sortantes 33 | Nombre maximal de connexions sortantes 34 | Nombre de connexions sortantes 35 | Nombre de connexions entrantes 36 | Nombre maximal de connexions entrantes 37 | Nombre de connexions entrantes 38 | Nœud amis 39 | Ajouter un nœud amis 40 | Ajouter un nœud amis 41 | Nœud exclusif 42 | Liste des nœuds exclusifs 43 | Nœud exclusif 44 | Nœud prioritaire 45 | Entrer un nœud prioritaire 46 | Nœud prioritaire 47 | Cette application permet de faire tourner un nœud de crypto monnaie Wownero sur votre téléphone. Pour faire des transactions en toute sécurité, connectez votre portefeuille sur ce nœud local. 48 | 1.1 49 | N/A 50 | Version logicielle du nœud Wownero 51 | Des idées pour nous aider? Des problèmes d\'utilisation. Rendez vous sur https://github.com/enerc/Aeon-daemon 52 | Votre avis 53 | Traces 54 | Contenus des traces 55 | Dons 56 | nœuds connectés 57 | Adresse sélectionnée 58 | Traces selectionnées 59 | Choisir un thème 60 | Thèmes 61 | Choisir un thème 62 | Thème 63 | Restreindre l\'accès RPC distant 64 | Empêche les inconnus d\'accéder à votre nœud. 65 | La synchronisation s\'est arrêtée 66 | nœuds connectés 67 | Télécharge à 68 | Utilise la carte SD 69 | Chemin 70 | Chemin sur la carte SD 71 | Utilise un chemin spécifique 72 | Emplacement des données de la bloc chaine 73 | Ces données ne seront pas supprimée quand l\'application est désinstallée 74 | Synchronisation rapide des blocs 75 | Utilise des blocs connus pour la synchonisation 76 | GB libre 77 | Le process de synchonisation ne tourne pas 78 | Début de synchronisation 79 | Configuration invalide 80 | Sélection simultanée de la carte SD et d\'un emplacement spécifique incompatible 81 | 0 = s\'adapte automatiquement 82 | Nombre de blocs pour la synchronisation 83 | Niveau de trace 84 | Niveau 85 | Chosir le niveau de trace 86 | Stockage 87 | Paramètres réseau 88 | Nœuds 89 | Bande passante 90 | Nœuds amis 91 | Sécurité 92 | Traces 93 | 94 | 95 | Erreur 96 | Info 97 | Debug 98 | Trace 99 | 100 | 101 | 102 | 0 103 | 1 104 | 2 105 | 3 106 | 107 | 108 | 109 | Couleur unie 110 | Coin WOW 111 | Wownario 112 | WOW! 113 | 114 | 115 | 116 | PreferencesThemeWownero1 117 | PreferencesThemeWownero2 118 | PreferencesThemeWownero3 119 | PreferencesThemeWownero4 120 | 121 | 122 | Dons Wownero 123 | Dons XMR 124 | Qui suis-je? 125 | Bloc 126 | Dernier bloc 127 | Pruning de la blockchain 128 | Réduit la taille sur le disque 129 | 130 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #2c89a0 5 | #303F9F 6 | #FF4081 7 | 8 | 9 | #FF6C60 10 | #222222 11 | #0F0F0F 12 | #FFF 13 | #76ff03 14 | #2196F3 15 | #808080 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | pocketnode 3 | 4 | storage 5 | Network settings 6 | Nodes 7 | Bandwith 8 | Peers 9 | Security 10 | Logs 11 | 12 | Settings 13 | Settings 14 | About 15 | 16 | About 17 | Block Height 18 | Latest Block 19 | 20 | Testnet 21 | Run on testnet. 22 | Testnet 23 | 24 | Stagenet 25 | Run on stagenet. 26 | Stagenet 27 | 28 | p2pBindPort 29 | Leave blank for default ports 30 | P2P Port 31 | 32 | rpcBindPort 33 | Leave blank for default ports 34 | RPC Port 35 | 36 | zmqBindPort 37 | Leave blank for 127.0.0.1 38 | ZMQ RPC server 39 | 40 | limitRate 41 | Set limit-rate [kB/s] 42 | Limit rate 43 | 44 | limitRateDown 45 | Set limit-rate [kB/s] 46 | Limit download rate 47 | 48 | limitRateUp 49 | Set limit-rate [kB/s] 50 | Limit upload rate 51 | 52 | outPeers 53 | Set max number of out peers 54 | Out peers 55 | 56 | inPeers 57 | Set max number of in peers 58 | In peers 59 | 60 | peerNode 61 | Manually add peer to local peerlist 62 | Add peer 63 | 64 | exclusiveNode 65 | Specify list of peers to connect to only (ip:port) 66 | Exclusive node 67 | 68 | priorityNode 69 | Specify a peer to connect (ip:port) 70 | Priority node 71 | 72 | This app is designed to run a Monero node locally on your Android device. Connect your wallet to the Node Address on the Main screen to use this node. Please file Bugs/Issues/Feature requests on the xmr-pocket-node code repo 73 | 1.1 74 | N/A 75 | Wownero daemon version 76 | Got an issue or having ideas to improve this app? We are happy to help at https://github.com/enerc/Aeon-daemon 77 | Feedback 78 | 79 | Logs 80 | Log content....... 81 | Donations 82 | WOW donation 83 | xmr donation 84 | Wownero 85 | Wo3tBXLr9Sq7cyqHiwoYTTGc4EfPidFFUN6rPv4RdrWc1boYemdNsRyFbpq1nnDAbRYTb8QArzF86Be1AuiabmqA37mTGhw1u 86 | Support 85-Year-Old Developers. Buy Grampy a Coffee: 87 | 8BudmXKZwpXhfVGCtgFPyKWgLcDLYJ5jRT95xCp4JMFWapgTLrun41AG6LPbef7WFA8T531QGnZT51cDF6uF9HECDhibEVw 88 | about this app 89 | 90 | Version 91 | peers connected 92 | Address selected 93 | Logs selected 94 | 95 | Choose a theme 96 | Theme 97 | Select a theme 98 | Theme 99 | 100 | Restricted RPC access 101 | Prevents external users to access your node 102 | Aeon daemon stopped syncing 103 | peers connected 104 | Download at 105 | 106 | 107 | Use SD card 108 | 109 | Location 110 | SD card location 111 | Use custom storage location 112 | 113 | Define your own blockchain storage location 114 | Data won\'t be removed when uninstalling this app 115 | Start Node 116 | Enable/Disable your node 117 | Fast bloc sync 118 | Sync up most of the way by using embedded, known block hashes. 119 | GB free 120 | 🔴 disconnected 121 | 🟢 Connected 122 | Synchronization Starting 123 | 124 | Invalid settings 125 | Custom and SD storage can\'t be set at the same time 126 | 127 | 128 | 129 | Error 130 | Info 131 | Debug 132 | Trace 133 | 134 | 135 | 136 | 0 137 | 1 138 | 2 139 | 3 140 | 141 | 142 | 143 | Solid color 144 | WOW coin 145 | Wownario 146 | WOW! 147 | 148 | 149 | 150 | PreferencesThemeWownero1 151 | PreferencesThemeWownero2 152 | PreferencesThemeWownero3 153 | PreferencesThemeWownero4 154 | 155 | 156 | 157 | 158 | 0 = adaptive 159 | Bloc sync size 160 | Log level 161 | Level 162 | Select the daemon log level 163 | 164 | Prune blockchain 165 | Reduce stored size 166 | 167 | 168 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 36 | 45 | 54 | 62 | 63 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/xml/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | 15 | 20 | 24 | 29 | 33 | 34 | 35 | 36 | 41 | 42 | 47 | 48 | 53 | 54 | 59 | 60 | 65 | 66 | 71 | 72 | 77 | 78 | 83 | 84 | 85 | 86 | 87 | 91 | 92 | 96 | 97 | 101 | 102 | 103 | 104 | 109 | 110 | 115 | 116 | 121 | 122 | 123 | 124 | 129 | 130 | 135 | 136 | 137 | 138 | 143 | 144 | 145 | 146 | 155 | 156 | 157 | 162 | 163 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 15 | 16 | 17 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/test/java/org/aeon/aeondaemon/app/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package org.aeon.aeondaemon.app; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /assets/pocketnode-inspiration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoGrampy/xmr-pocket-node/1a4b77d7b4f7e69a87bf24874936ba915cf26b44/assets/pocketnode-inspiration.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:7.1.2' 11 | 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | maven { 23 | url 'https://www.jitpack.io' 24 | } 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /monero-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | Created with Fabric.js 1.7.22 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------