diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6aa61eeb..d16041f6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,7 +14,7 @@
android:largeHeap="true"
android:theme="@style/AppTheme" >
@@ -28,11 +28,22 @@
+
+
+
+
+
diff --git a/app/src/main/java/org/ethereum/android_app/ActivityInterface.java b/app/src/main/java/org/ethereum/android_app/ActivityInterface.java
index 8dcee763..8bdc6411 100644
--- a/app/src/main/java/org/ethereum/android_app/ActivityInterface.java
+++ b/app/src/main/java/org/ethereum/android_app/ActivityInterface.java
@@ -1,8 +1,6 @@
package org.ethereum.android_app;
-import android.support.v4.app.Fragment;
-
public interface ActivityInterface {
void registerFragment(FragmentInterface fragment);
diff --git a/app/src/main/java/org/ethereum/android_app/MainActivity.java b/app/src/main/java/org/ethereum/android_app/AidlMainActivity.java
similarity index 81%
rename from app/src/main/java/org/ethereum/android_app/MainActivity.java
rename to app/src/main/java/org/ethereum/android_app/AidlMainActivity.java
index fa6a5add..d2641201 100644
--- a/app/src/main/java/org/ethereum/android_app/MainActivity.java
+++ b/app/src/main/java/org/ethereum/android_app/AidlMainActivity.java
@@ -4,11 +4,9 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.AsyncTask;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
-import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
@@ -16,10 +14,8 @@ import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-import android.os.Build;
import android.widget.Toast;
-import org.ethereum.android.EthereumManager;
import org.ethereum.android.interop.IEthereumService;
import org.ethereum.android.interop.IListener;
import org.ethereum.config.SystemProperties;
@@ -28,7 +24,7 @@ import java.io.File;
import java.util.ArrayList;
-public class MainActivity extends ActionBarActivity implements ActivityInterface {
+public class AidlMainActivity extends ActionBarActivity implements ActivityInterface {
private static final String TAG = "MyActivity";
@@ -67,7 +63,7 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
ethereumService = IEthereumService.Stub.asInterface(service);
- Toast.makeText(MainActivity.this, "service attached", Toast.LENGTH_SHORT).show();
+ Toast.makeText(AidlMainActivity.this, "service attached", Toast.LENGTH_SHORT).show();
try {
@@ -93,7 +89,7 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
SystemProperties.CONFIG.activePeerPort(),
SystemProperties.CONFIG.activePeerNodeid());
}
- Toast.makeText(MainActivity.this, "connected to service", Toast.LENGTH_SHORT).show();
+ Toast.makeText(AidlMainActivity.this, "connected to service", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
logMessage("Error adding listener: " + e.getMessage());
}
@@ -104,7 +100,7 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
ethereumService = null;
- Toast.makeText(MainActivity.this, "service disconnected", Toast.LENGTH_SHORT).show();
+ Toast.makeText(AidlMainActivity.this, "service disconnected", Toast.LENGTH_SHORT).show();
}
};
@@ -125,7 +121,7 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
tabs.setDistributeEvenly(true);
tabs.setViewPager(viewPager);
- ComponentName myService = startService(new Intent(MainActivity.this, EthereumService.class));
+ ComponentName myService = startService(new Intent(AidlMainActivity.this, EthereumService.class));
doBindService();
//StrictMode.enableDefaults();
@@ -133,13 +129,13 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
protected void logMessage(String message) {
- MainActivity.consoleLog += message + "\n";
- int consoleLength = MainActivity.consoleLog.length();
+ AidlMainActivity.consoleLog += message + "\n";
+ int consoleLength = AidlMainActivity.consoleLog.length();
if (consoleLength > 5000) {
- MainActivity.consoleLog = MainActivity.consoleLog.substring(4000);
+ AidlMainActivity.consoleLog = AidlMainActivity.consoleLog.substring(4000);
}
- broadcastFragments(MainActivity.consoleLog);
+ broadcastFragments(AidlMainActivity.consoleLog);
}
@@ -155,9 +151,9 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
// Establish a connection with the service. We use an explicit
// class name because there is no reason to be able to let other
// applications replace our component.
- bindService(new Intent(MainActivity.this, EthereumService.class), serviceConnection, Context.BIND_AUTO_CREATE);
+ bindService(new Intent(AidlMainActivity.this, EthereumService.class), serviceConnection, Context.BIND_AUTO_CREATE);
isBound = true;
- Toast.makeText(MainActivity.this, "binding to service", Toast.LENGTH_SHORT).show();
+ Toast.makeText(AidlMainActivity.this, "binding to service", Toast.LENGTH_SHORT).show();
}
void doUnbindService() {
@@ -177,7 +173,7 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
// Detach our existing connection.
unbindService(serviceConnection);
isBound = false;
- Toast.makeText(MainActivity.this, "unbinding from service", Toast.LENGTH_SHORT).show();
+ Toast.makeText(AidlMainActivity.this, "unbinding from service", Toast.LENGTH_SHORT).show();
}
}
@@ -191,7 +187,6 @@ public class MainActivity extends ActionBarActivity implements ActivityInterface
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- //return super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
diff --git a/app/src/main/java/org/ethereum/android_app/EthereumApplication.java b/app/src/main/java/org/ethereum/android_app/EthereumApplication.java
index acbc416c..e6931d8f 100644
--- a/app/src/main/java/org/ethereum/android_app/EthereumApplication.java
+++ b/app/src/main/java/org/ethereum/android_app/EthereumApplication.java
@@ -3,11 +3,23 @@ package org.ethereum.android_app;
import android.support.multidex.MultiDexApplication;
+import org.ethereum.android.service.EthereumConnector;
+
public class EthereumApplication extends MultiDexApplication {
- @Override public void onCreate() {
- super.onCreate();
+ EthereumConnector ethereum = null;
+ @Override public void onCreate() {
+
+ super.onCreate();
+ ethereum = new EthereumConnector(this, EthereumRemoteService.class);
+ ethereum.bindService();
}
+ @Override
+ public void onTerminate() {
+
+ super.onTerminate();
+ ethereum.unbindService();
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/ethereum/android_app/EthereumRemoteService.java b/app/src/main/java/org/ethereum/android_app/EthereumRemoteService.java
new file mode 100644
index 00000000..fd91c19e
--- /dev/null
+++ b/app/src/main/java/org/ethereum/android_app/EthereumRemoteService.java
@@ -0,0 +1,10 @@
+package org.ethereum.android_app;
+
+
+public class EthereumRemoteService extends org.ethereum.android.service.EthereumRemoteService {
+
+ public EthereumRemoteService() {
+
+ super();
+ }
+}
diff --git a/app/src/main/java/org/ethereum/android_app/EthereumService.java b/app/src/main/java/org/ethereum/android_app/EthereumService.java
index 65d78e92..7ea9d376 100644
--- a/app/src/main/java/org/ethereum/android_app/EthereumService.java
+++ b/app/src/main/java/org/ethereum/android_app/EthereumService.java
@@ -1,6 +1,6 @@
package org.ethereum.android_app;
-import org.ethereum.android.EthereumAidlService;
+import org.ethereum.android.service.EthereumAidlService;
import org.ethereum.android.interop.IListener;
public class EthereumService extends EthereumAidlService {
diff --git a/app/src/main/java/org/ethereum/android_app/RemoteMainActivity.java b/app/src/main/java/org/ethereum/android_app/RemoteMainActivity.java
new file mode 100644
index 00000000..ef19056b
--- /dev/null
+++ b/app/src/main/java/org/ethereum/android_app/RemoteMainActivity.java
@@ -0,0 +1,69 @@
+package org.ethereum.android_app;
+
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBarActivity;
+import android.os.Bundle;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import java.util.ArrayList;
+
+
+public class RemoteMainActivity extends ActionBarActivity implements ActivityInterface {
+
+ private Toolbar toolbar;
+ private ViewPager viewPager;
+ private SlidingTabLayout tabs;
+ private TabsPagerAdapter adapter;
+ protected ArrayList fragments = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ toolbar = (Toolbar) findViewById(R.id.tool_bar);
+ setSupportActionBar(toolbar);
+
+ adapter = new TabsPagerAdapter(getSupportFragmentManager());
+ viewPager = (ViewPager) findViewById(R.id.pager);
+ viewPager.setAdapter(adapter);;
+
+ tabs = (SlidingTabLayout) findViewById(R.id.tabs);
+ tabs.setDistributeEvenly(true);
+ tabs.setViewPager(viewPager);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_settings) {
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void registerFragment(FragmentInterface fragment) {
+
+ if (!fragments.contains(fragment)) {
+ fragments.add(fragment);
+ }
+ }
+}
diff --git a/app/src/main/java/org/ethereum/android_app/TestActivity.java b/app/src/main/java/org/ethereum/android_app/TestActivity.java
index 05cba35a..d7a84cc0 100644
--- a/app/src/main/java/org/ethereum/android_app/TestActivity.java
+++ b/app/src/main/java/org/ethereum/android_app/TestActivity.java
@@ -10,12 +10,14 @@ public class TestActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
+
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_test, menu);
return true;
@@ -23,6 +25,7 @@ public class TestActivity extends ActionBarActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
diff --git a/app/src/main/java/org/ethereum/android_app/TestsFragment.java b/app/src/main/java/org/ethereum/android_app/TestsFragment.java
index 47d6b825..5db25424 100644
--- a/app/src/main/java/org/ethereum/android_app/TestsFragment.java
+++ b/app/src/main/java/org/ethereum/android_app/TestsFragment.java
@@ -1,22 +1,132 @@
package org.ethereum.android_app;
import android.os.Bundle;
+import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
import org.ethereum.android.EthereumManager;
+import org.ethereum.android.interop.AdminInfo;
+import org.ethereum.android.service.ConnectorHandler;
+import org.ethereum.android.service.EthereumClientMessage;
+import org.ethereum.config.SystemProperties;
-public class TestsFragment extends Fragment {
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.UUID;
- EthereumManager ethereumManager;
+import static org.ethereum.config.SystemProperties.CONFIG;
+
+public class TestsFragment extends Fragment implements ConnectorHandler {
+
+ TextView connectionStatus;
+ TextView blockchainStatus;
+ TextView startupTime;
+ TextView isConsensus;
+ TextView blockExecTime;
+
+ Button connectButton;
+ Button getEthereumStatus;
+ Button getBlockchainStatus;
+
+ String identifier = UUID.randomUUID().toString();
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tests, container, false);
+
+ connectionStatus = (TextView)view.findViewById(R.id.connectionStatus);
+ blockchainStatus = (TextView)view.findViewById(R.id.blockchainStatus);
+ startupTime = (TextView)view.findViewById(R.id.startupTime);
+ isConsensus = (TextView)view.findViewById(R.id.isConsensus);
+ blockExecTime = (TextView)view.findViewById(R.id.blockExecTime);
+ connectButton = (Button)view.findViewById(R.id.connectButton);
+ getEthereumStatus = (Button)view.findViewById(R.id.getEthereumStatus);
+ getBlockchainStatus = (Button)view.findViewById(R.id.getBlockchainStatus);
+
+ connectButton.setOnClickListener(onClickListener);
+ getEthereumStatus.setOnClickListener(onClickListener);
+ getBlockchainStatus.setOnClickListener(onClickListener);
+
+ EthereumApplication app = (EthereumApplication)getActivity().getApplication();
+ app.ethereum.registerHandler(this);
+
return view;
}
+
+ private View.OnClickListener onClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+
+ EthereumApplication app = (EthereumApplication)getActivity().getApplication();
+ switch(v.getId()){
+ case R.id.connectButton:
+ app.ethereum.connect(CONFIG.activePeerIP(), CONFIG.activePeerPort(), CONFIG.activePeerNodeid());
+ break;
+ case R.id.getEthereumStatus:
+ app.ethereum.getConnectionStatus(identifier);
+ app.ethereum.getAdminInfo(identifier);
+ break;
+ case R.id.getBlockchainStatus:
+ app.ethereum.getBlockchainStatus(identifier);
+ break;
+ }
+ }
+ };
+
+ protected void updateTextView(final TextView view, final String text) {
+
+ view.post(new Runnable() {
+ @Override
+ public void run() {
+ view.setText(text);
+ }
+ });
+ }
+
+ @Override
+ public boolean handleMessage(final Message message) {
+
+ boolean isClaimed = true;
+ switch(message.what) {
+ case EthereumClientMessage.MSG_CONNECTION_STATUS:
+ updateTextView(connectionStatus, message.getData().getString("status"));
+ break;
+ case EthereumClientMessage.MSG_BLOCKCHAIN_STATUS:
+ updateTextView(blockchainStatus, message.getData().getString("status"));
+ break;
+ case EthereumClientMessage.MSG_ADMIN_INFO:
+ Bundle data = message.getData();
+ data.setClassLoader(AdminInfo.class.getClassLoader());
+ AdminInfo adminInfo = data.getParcelable("adminInfo");
+ updateTextView(startupTime, new SimpleDateFormat("yyyy MM dd HH:mm:ss").format(new Date(adminInfo.getStartupTimeStamp())));
+ updateTextView(isConsensus, adminInfo.isConsensus() ? "true" : "false");
+ updateTextView(blockExecTime, adminInfo.getExecAvg().toString());
+ break;
+ case EthereumClientMessage.MSG_ONLINE_PEER:
+ break;
+ case EthereumClientMessage.MSG_PEERS:
+ break;
+ case EthereumClientMessage.MSG_PENDING_TRANSACTIONS:
+ break;
+ case EthereumClientMessage.MSG_SUBMIT_TRANSACTION_RESULT:
+ break;
+ default:
+ isClaimed = false;
+ }
+ return isClaimed;
+ }
+
+ @Override
+ public String getID() {
+
+ return identifier;
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_remote_main.xml b/app/src/main/res/layout/activity_remote_main.xml
new file mode 100644
index 00000000..78df55dc
--- /dev/null
+++ b/app/src/main/res/layout/activity_remote_main.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_tests.xml b/app/src/main/res/layout/fragment_tests.xml
index 43783032..5fb17cf0 100644
--- a/app/src/main/res/layout/fragment_tests.xml
+++ b/app/src/main/res/layout/fragment_tests.xml
@@ -7,5 +7,162 @@
android:gravity="center"
android:text="@string/ethereumj_tests"
android:textSize="20sp"
- android:layout_centerInParent="true"/>
+ android:id="@+id/textView2"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
index b1cb9081..d7308e9d 100644
--- a/app/src/main/res/menu/menu_main.xml
+++ b/app/src/main/res/menu/menu_main.xml
@@ -1,6 +1,7 @@
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 32214cd2..37b8f264 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -9,5 +9,6 @@
TestActivity
Hello world!
+ RemoteMainActivity
diff --git a/ethereumj-core-android/src/main/AndroidManifest.xml b/ethereumj-core-android/src/main/AndroidManifest.xml
index 3e0e6a8d..769f4d81 100644
--- a/ethereumj-core-android/src/main/AndroidManifest.xml
+++ b/ethereumj-core-android/src/main/AndroidManifest.xml
@@ -6,7 +6,7 @@
android:allowBackup="true"
android:label="@string/app_name" >
@@ -15,13 +15,13 @@
diff --git a/ethereumj-core-android/src/main/assets/logback.xml b/ethereumj-core-android/src/main/assets/logback.xml
index c488e8ef..07566cd3 100644
--- a/ethereumj-core-android/src/main/assets/logback.xml
+++ b/ethereumj-core-android/src/main/assets/logback.xml
@@ -4,7 +4,7 @@
- ERROR
+ INFO
ACCEPT
DENY
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java
index a05b708c..96c4e954 100644
--- a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java
@@ -2,8 +2,6 @@ package org.ethereum.android;
import android.content.Context;
-import com.j256.ormlite.android.apptools.OpenHelperManager;
-
import org.ethereum.android.di.modules.EthereumModule;
import org.ethereum.android.di.components.DaggerEthereumComponent;
import org.ethereum.config.SystemProperties;
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumRemoteService.java b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumRemoteService.java
deleted file mode 100644
index a10dd555..00000000
--- a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumRemoteService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.ethereum.android;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class EthereumRemoteService extends Service {
- public EthereumRemoteService() {
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- // TODO: Return the communication channel to the service.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumService.java b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumService.java
deleted file mode 100644
index 6019505f..00000000
--- a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumService.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.ethereum.android;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class EthereumService extends Service {
- public EthereumService() {
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- // TODO: Return the communication channel to the service.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/interop/AdminInfo.java b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/AdminInfo.java
new file mode 100644
index 00000000..6ccc385e
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/AdminInfo.java
@@ -0,0 +1,82 @@
+package org.ethereum.android.interop;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AdminInfo extends org.ethereum.manager.AdminInfo implements Parcelable {
+
+ public AdminInfo(org.ethereum.manager.AdminInfo adminInfo) {
+
+ startupTimeStamp = adminInfo.getStartupTimeStamp();
+ consensus = adminInfo.isConsensus();
+ blockExecTime = adminInfo.getBlockExecTime();
+ }
+
+ @Override
+ public int describeContents() {
+
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+
+ parcel.writeLong(getStartupTimeStamp());
+ parcel.writeByte((byte) (isConsensus() ? 1 : 0));
+ parcel.writeLongArray(listToArray(getBlockExecTime()));
+ }
+
+ private long[] listToArray(List list) {
+
+ int length = list.size();
+ int arrayLength = 0;
+ for (int i = 0; i < length; i++) {
+ if (list.get(i) != null) {
+ arrayLength++;
+ }
+ }
+ long[] array = new long[arrayLength];
+ int arrayIndex = 0;
+ for (int i = 0; i < length; i++) {
+ Long item = list.get(i);
+ if (item != null) {
+ array[arrayIndex] = item;
+ arrayIndex++;
+ }
+ }
+ return array;
+ }
+
+ private List arrayToList(long[] array) {
+
+ ArrayList list = new ArrayList<>(array.length);
+ for (long item : array) {
+ list.add(item);
+ }
+ return list;
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+
+ public AdminInfo createFromParcel(Parcel in) {
+
+ return new AdminInfo(in);
+ }
+
+ public AdminInfo[] newArray(int size) {
+
+ return new AdminInfo[size];
+ }
+ };
+
+ private AdminInfo(Parcel in) {
+
+ startupTimeStamp = in.readLong();
+ consensus = in.readByte() == 1 ? true : false;
+ blockExecTime = arrayToList(in.createLongArray());
+ }
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/interop/PeerInfo.java b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/PeerInfo.java
new file mode 100644
index 00000000..7496fe30
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/PeerInfo.java
@@ -0,0 +1,61 @@
+package org.ethereum.android.interop;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class PeerInfo extends org.ethereum.net.peerdiscovery.PeerInfo implements Parcelable {
+
+ public PeerInfo(InetAddress ip, int port, String peerId) {
+
+ super(ip, port, peerId);
+ }
+
+ public PeerInfo(org.ethereum.net.peerdiscovery.PeerInfo peerInfo) {
+
+ super(peerInfo.getAddress(), peerInfo.getPort(), peerInfo.getPeerId());
+ }
+
+ @Override
+ public int describeContents() {
+
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+
+ parcel.writeByteArray(address.getAddress());
+ parcel.writeInt(port);
+ parcel.writeString(peerId);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+
+ public PeerInfo createFromParcel(Parcel in) {
+
+ return new PeerInfo(in);
+ }
+
+ public PeerInfo[] newArray(int size) {
+
+ return new PeerInfo[size];
+ }
+ };
+
+ private PeerInfo(Parcel in) {
+
+ super(null, 0, "");
+ InetAddress ip = null;
+ try {
+ address = InetAddress.getByAddress(in.createByteArray());
+ } catch (UnknownHostException e) {
+
+ }
+ port = in.readInt();
+ peerId = in.readString();
+ }
+
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/interop/Transaction.java b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/Transaction.java
new file mode 100644
index 00000000..0cab68f9
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/interop/Transaction.java
@@ -0,0 +1,44 @@
+package org.ethereum.android.interop;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class Transaction extends org.ethereum.core.Transaction implements Parcelable{
+
+
+ public Transaction(org.ethereum.core.Transaction transaction) {
+
+ super(transaction.getEncoded());
+ }
+
+ @Override
+ public int describeContents() {
+
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+
+ parcel.writeByteArray(getEncoded());
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+
+ public Transaction createFromParcel(Parcel in) {
+
+ return new Transaction(in);
+ }
+
+ public Transaction[] newArray(int size) {
+
+ return new Transaction[size];
+ }
+ };
+
+ private Transaction(Parcel in) {
+
+ super(in.createByteArray());
+ }
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/ConnectorHandler.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/ConnectorHandler.java
new file mode 100644
index 00000000..e0d66250
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/ConnectorHandler.java
@@ -0,0 +1,10 @@
+package org.ethereum.android.service;
+
+
+import android.os.Message;
+
+public interface ConnectorHandler {
+
+ boolean handleMessage(Message message);
+ String getID();
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumAidlService.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumAidlService.java
new file mode 100644
index 00000000..a54132f6
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumAidlService.java
@@ -0,0 +1,101 @@
+package org.ethereum.android.service;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import org.ethereum.android.jsonrpc.JsonRpcServer;
+import org.ethereum.android.manager.BlockLoader;
+import org.ethereum.android.interop.*;
+
+import java.util.ArrayList;
+
+public class EthereumAidlService extends EthereumService {
+
+ protected ArrayList clientListeners = new ArrayList<>();
+
+ public static String log = "";
+
+ IEthereumService.Stub binder = null;
+
+ public EthereumAidlService() {
+
+ initializeBinder();
+ }
+
+ protected void initializeBinder() {
+
+ binder = new IEthereumService.Stub() {
+
+ public void loadBlocks(String dumpFile) throws RemoteException {
+
+ BlockLoader blockLoader = (BlockLoader)ethereum.getBlockLoader();
+ blockLoader.loadBlocks(dumpFile);
+ }
+
+ public void connect(String ip, int port, String remoteId) throws RemoteException {
+
+ if (!isConnected) {
+ System.out.println("Connecting to : " + ip);
+ ethereum.connect(ip, port, remoteId);
+ isConnected = true;
+ } else {
+ System.out.println("Already connected");
+ System.out.println("x " + ethereum.isConnected());
+ }
+ }
+
+ public void addListener(IListener listener) throws RemoteException {
+
+ clientListeners.clear();
+ clientListeners.add(listener);
+ }
+
+ public void removeListener(IListener listener) throws RemoteException {
+
+ try {
+ clientListeners.remove(listener);
+ } catch (Exception e) {
+ System.out.println("ERRORRRR: " + e.getMessage());
+ }
+ }
+
+ public void startJsonRpcServer() throws RemoteException {
+
+ jsonRpcServer = new JsonRpcServer(ethereum);
+ }
+
+ public void getLog(IAsyncCallback callback) throws RemoteException {
+
+ callback.handleResponse(EthereumAidlService.log);
+ }
+ };
+ }
+
+ @Override
+ protected void broadcastMessage(String message) {
+
+ for (IListener listener: clientListeners) {
+ try {
+ listener.trace(message);
+ } catch (Exception e) {
+ // Remove listener
+ System.out.println("ERRORRRR: " + e.getMessage());
+ clientListeners.remove(listener);
+ }
+ }
+ }
+
+ @Override
+ public void onCreate() {
+
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+
+ return binder;
+ }
+
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumClientMessage.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumClientMessage.java
new file mode 100644
index 00000000..242dc69b
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumClientMessage.java
@@ -0,0 +1,39 @@
+package org.ethereum.android.service;
+
+public class EthereumClientMessage {
+
+ /**
+ * Send online peer to the client ("peerInfo" => PeerInfo)
+ */
+ public static final int MSG_ONLINE_PEER = 1;
+
+ /**
+ * Send peers to the client ("peers" => PeerInfo[])
+ */
+ public static final int MSG_PEERS = 2;
+
+ /**
+ * Send blockchain status to the client ("status" => "Loaded/Loading")
+ */
+ public static final int MSG_BLOCKCHAIN_STATUS = 3;
+
+ /**
+ * Send ethereum connection status to the client
+ */
+ public static final int MSG_CONNECTION_STATUS = 4;
+
+ /**
+ * Send submitted transaction to client
+ */
+ public static final int MSG_SUBMIT_TRANSACTION_RESULT = 5;
+
+ /**
+ * Send admin info to client
+ */
+ public static final int MSG_ADMIN_INFO = 6;
+
+ /**
+ * Send peers to the client
+ */
+ public static final int MSG_PENDING_TRANSACTIONS = 7;
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumConnector.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumConnector.java
new file mode 100644
index 00000000..a03650e4
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumConnector.java
@@ -0,0 +1,391 @@
+package org.ethereum.android.service;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.RemoteException;
+
+import org.ethereum.core.Transaction;
+import org.ethereum.net.peerdiscovery.PeerInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EthereumConnector extends ServiceConnector {
+
+ private static final Logger logger = LoggerFactory.getLogger("EthereumConnector");
+
+ public EthereumConnector(Context context, Class serviceClass) {
+
+ super(context, serviceClass);
+ }
+
+ /**
+ * Connect ethereum to peer
+ * @param ip String Peer ip address
+ * @param port int Peer port
+ * @param remoteId String Peer remote id
+ *
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "ip": String [Peer ip address]
+ * "port": int [Peer port]
+ * "remoteId": String [Peer remote id]
+ * }
+ */
+ public void connect(String ip, int port, String remoteId) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_CONNECT, 0, 0);
+ Bundle data = new Bundle();
+ data.putString("ip", ip);
+ data.putInt("port", port);
+ data.putString("remoteId", remoteId);
+ msg.setData(data);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(connect) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Load blocks from dump file
+ * @param dumpFile String Blocks dump file path
+ *
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "dumpFile": String [Blocks dump file paths]
+ * }
+ */
+ public void loadBlocks(String dumpFile) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_LOAD_BLOCKS, 0, 0);
+ Bundle data = new Bundle();
+ data.putString("dumpFile", dumpFile);
+ msg.setData(data);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(loadBlocks) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Start the json rpc server
+ *
+ * Sends message parameters: none
+ */
+ public void startJsonRpc() {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_START_JSON_RPC_SERVER, 0, 0);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(startJsonRpc) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Find an online peer
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void findOnlinePeer(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_FIND_ONLINE_PEER, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(findOnlinePeer1) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Find an online peer
+ * @param identifier String Caller identifier used to return the response
+ * @param excludePeer PeerInfo Excluded peer from search
+ *
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "excludePeer": Parcelable(PeerInfo) [Exclude peer from search]
+ * }
+ */
+ public void findOnlinePeer(String identifier, PeerInfo excludePeer) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_FIND_ONLINE_PEER, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ Bundle data = new Bundle();
+ data.putParcelable("excludePeer", (org.ethereum.android.interop.PeerInfo)excludePeer);
+ msg.setData(data);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(findOnlinePeer2) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Find an online peer
+ * @param identifier String Caller identifier used to return the response
+ * @param excludePeerSet PeerInfo[] Excluded peers from search
+ *
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "excludePeerSet": ParcelableArray(PeerInfo[]) [Excluded peers from search]
+ * }
+ */
+ public void findOnlinePeer(String identifier, PeerInfo[] excludePeerSet) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_FIND_ONLINE_PEER, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ Bundle data = new Bundle();
+ data.putParcelableArray("excludePeerSet", (org.ethereum.android.interop.PeerInfo[]) excludePeerSet);
+ msg.setData(data);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(findOnlinePeer3) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get etherum peers
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void getPeers(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_GET_PEERS, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(getPeers) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Starts ethereum peer discovery
+ *
+ * Sends message parameters: none
+ */
+ public void startPeerDiscovery() {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_START_PEER_DISCOVERY, 0, 0);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(startPeerDiscovery) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Stops ethereum peer discovery
+ *
+ * Sends message parameters: none
+ */
+ public void stopPeerDiscovery() {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_LOAD_BLOCKS, 0, 0);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(stopPeerDiscovery) to service: " + e.getMessage());
+ }
+ }
+
+ protected Bundle getIdentifierBundle(String identifier) {
+
+ Bundle bundle = new Bundle();
+ bundle.putString("identifier", identifier);
+ return bundle;
+ }
+
+
+ /**
+ * Gets the blockchain status
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void getBlockchainStatus(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_GET_BLOCKCHAIN_STATUS, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(getBlockchainStatus) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Add ethereum event listener
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void addListener(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_ADD_LISTENER, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ // TODO: Add event flags to message
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(addListener) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Closes ethereum
+ *
+ * Sends message parameters: none
+ */
+ public void closeEthereum() {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_CLOSE, 0, 0);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(closeEthereum) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get connection status
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void getConnectionStatus(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_GET_CONNECTION_STATUS, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(getConnectionStatus) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Submit ethereum transaction
+ * @param identifier String Caller identifier used to return the response
+ * @param transaction Transaction Transaction to submit
+ *
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "transaction": Parcelable(Transaction) [transaction to submit]
+ * }
+ */
+ public void submitTransaction(String identifier, Transaction transaction) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_SUBMIT_TRANSACTION, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ Bundle data = new Bundle();
+ data.putParcelable("transaction", (org.ethereum.android.interop.Transaction)transaction);
+ msg.setData(data);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(submitTransaction) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get admin info
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void getAdminInfo(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_GET_ADMIN_INFO, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(getAdminInfo) to service: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get pending transactions
+ * @param identifier String Caller identifier used to return the response
+ *
+ * Sends message parameters: none
+ */
+ public void getPendingTransactions(String identifier) {
+
+ if (!isBound)
+ return;
+
+ Message msg = Message.obtain(null, EthereumServiceMessage.MSG_GET_PENDING_TRANSACTIONS, 0, 0);
+ msg.replyTo = clientMessenger;
+ msg.obj = getIdentifierBundle(identifier);
+ try {
+ serviceMessenger.send(msg);
+ } catch (RemoteException e) {
+ logger.error("Exception sending message(getPendingTransactions) to service: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumRemoteService.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumRemoteService.java
new file mode 100644
index 00000000..1aa90915
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumRemoteService.java
@@ -0,0 +1,542 @@
+package org.ethereum.android.service;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+
+import org.ethereum.android.jsonrpc.JsonRpcServer;
+import org.ethereum.android.manager.BlockLoader;
+import org.ethereum.core.Transaction;
+import org.ethereum.facade.Ethereum;
+import org.ethereum.manager.AdminInfo;
+import org.ethereum.net.peerdiscovery.PeerInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import static org.ethereum.config.SystemProperties.CONFIG;
+
+public class EthereumRemoteService extends EthereumService {
+
+ private static final Logger logger = LoggerFactory.getLogger("EthereumRemoteService");
+
+ ArrayList clientListeners = new ArrayList<>();
+
+ public EthereumRemoteService() {
+
+ super();
+ }
+
+ /** Handles incoming messages from clients. */
+ static class IncomingHandler extends Handler {
+
+ private final WeakReference service;
+
+ IncomingHandler(EthereumRemoteService service) {
+
+ this.service = new WeakReference(service);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+
+ EthereumRemoteService service = this.service.get();
+ if (service != null) {
+ if (!service.handleMessage(message)) {
+ super.handleMessage(message);
+ }
+ }
+ }
+ }
+
+ /**
+ * Target we publish for clients to send messages to IncomingHandler.Note
+ * that calls to its binder are sequential!
+ */
+ final Messenger serviceMessenger = new Messenger(new IncomingHandler(this));
+
+ /**
+ * When binding to the service, we return an interface to our messenger for
+ * sending messages to the service.
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+
+ return serviceMessenger.getBinder();
+ }
+
+ @Override
+ public void onCreate() {
+
+ super.onCreate();
+ }
+
+ protected boolean handleMessage(Message message) {
+
+ switch (message.what) {
+
+ case EthereumServiceMessage.MSG_CONNECT:
+ connect(message);
+ break;
+
+ case EthereumServiceMessage.MSG_LOAD_BLOCKS:
+ loadBlocks(message);
+ break;
+
+ case EthereumServiceMessage.MSG_START_JSON_RPC_SERVER:
+ startJsonRpc(message);
+ break;
+
+ case EthereumServiceMessage.MSG_FIND_ONLINE_PEER:
+ findOnlinePeer(message);
+ break;
+
+ case EthereumServiceMessage.MSG_GET_PEERS:
+ getPeers(message);
+ break;
+
+ case EthereumServiceMessage.MSG_START_PEER_DISCOVERY:
+ startPeerDiscovery(message);
+ break;
+
+ case EthereumServiceMessage.MSG_STOP_PEER_DISCOVERY:
+ stopPeerDiscovery(message);
+ break;
+
+ case EthereumServiceMessage.MSG_GET_BLOCKCHAIN_STATUS:
+ getBlockchainStatus(message);
+ break;
+
+ case EthereumServiceMessage.MSG_ADD_LISTENER:
+ addListener(message);
+ break;
+
+ case EthereumServiceMessage.MSG_GET_CONNECTION_STATUS:
+ getConnectionStatus(message);
+ break;
+
+ case EthereumServiceMessage.MSG_CLOSE:
+ closeEthereum(message);
+ break;
+
+ case EthereumServiceMessage.MSG_SUBMIT_TRANSACTION:
+ submitTransaction(message);
+ break;
+
+ case EthereumServiceMessage.MSG_GET_ADMIN_INFO:
+ getAdminInfo(message);
+ break;
+
+ case EthereumServiceMessage.MSG_GET_PENDING_TRANSACTIONS:
+ getPendingTransactions(message);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Connect to peer
+ *
+ * Incoming message parameters ( "key": type [description] ):
+ * {
+ * "ip": String [peer ip address]
+ * "port": int [peer port]
+ * "remoteId": String [peer remoteId]
+ * }
+ * Sends message: none
+ */
+ protected void connect(Message message) {
+
+ if (!isConnected) {
+ isConnected = true;
+ new ConnectTask(message).execute(ethereum);
+ }
+ }
+
+ protected class ConnectTask extends AsyncTask {
+
+ String ip;
+ int port;
+ String remoteId;
+
+ public ConnectTask(Message message) {
+
+ Bundle data = message.getData();
+ ip = data.getString("ip");
+ port = data.getInt("port");
+ remoteId = data.getString("remoteId");
+ }
+
+ protected Void doInBackground(Ethereum... args) {
+
+ Ethereum ethereum = args[0];
+ ethereum.connect(ip, port, remoteId);
+ logger.info("Ethereum connecting to : " + ip + ":" + port);
+ return null;
+ }
+
+ protected void onPostExecute(Void results) {
+
+
+ }
+ }
+
+ /**
+ * Load blocks from dump file
+ *
+ * Incoming message parameters ( "key": type [description] ):
+ * {
+ * "dumpFile": String [blocks dump file path]
+ * }
+ * Sends message: none
+ */
+ protected void loadBlocks(Message message) {
+
+ if (!isConnected) {
+ isConnected = true;
+ new LoadBlocksTask(message).execute(ethereum);
+ }
+ }
+
+ protected class LoadBlocksTask extends AsyncTask {
+
+ String dumpFile;
+
+ public LoadBlocksTask(Message message) {
+
+ Bundle data = message.getData();
+ dumpFile = data.getString("dumpFile");
+ }
+
+ protected Void doInBackground(Ethereum... args) {
+
+ Ethereum ethereum = args[0];
+ logger.info("Loading blocks from: " + dumpFile);
+ BlockLoader blockLoader = (BlockLoader)ethereum.getBlockLoader();
+ blockLoader.loadBlocks(dumpFile);
+ logger.info("Finished loading blocks from: " + dumpFile);
+ return null;
+ }
+
+ protected void onPostExecute(Void results) {
+
+
+ }
+ }
+
+ /**
+ * Start the json rpc server
+ *
+ * Incoming message parameters: none
+ * Sends message: none
+ */
+ protected void startJsonRpc(Message message) {
+
+ // TODO: Maybe send back if it started succesfully ?
+ jsonRpcServer = new JsonRpcServer(ethereum);
+ try {
+ jsonRpcServer.start();
+ logger.info("Started json rpc server!");
+ } catch (Exception e) {
+ logger.error("Exception starting json rpc server: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Find an online peer
+ *
+ * Incoming message parameters ( "key": type [description] ):
+ * {
+ * "excludePeer": Parcelable(PeerInfo) [peer to exclude from search]
+ * }
+ * Sends message parameters ( "key": type [description] ):
+ * {
+ * "peerInfo": Parcelable(PeerInfo) [found online peer, or null if error / online peer not found]
+ * }
+ */
+ protected void findOnlinePeer(Message message) {
+
+ Bundle data = message.getData();
+ PeerInfo foundPeerInfo;
+ PeerInfo peerInfo = data.getParcelable("excludePeer");
+ if (peerInfo != null) {
+ foundPeerInfo = ethereum.findOnlinePeer(peerInfo);
+ } else {
+ PeerInfo[] excludePeerSet = (PeerInfo[])data.getParcelableArray("excludePeerSet");
+ if (excludePeerSet != null) {
+ foundPeerInfo = ethereum.findOnlinePeer(new HashSet<>(Arrays.asList(excludePeerSet)));
+ } else {
+ foundPeerInfo = ethereum.findOnlinePeer();
+ }
+ }
+ // Send reply
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_ONLINE_PEER, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ replyData.putParcelable("peerInfo", new org.ethereum.android.interop.PeerInfo(foundPeerInfo));
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent online peer to client: " + foundPeerInfo.toString());
+ } catch (RemoteException e) {
+ logger.error("Exception sending online peer to client: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get etherum peers
+ *
+ * Incoming message parameters: none
+ * Sends message ( "key": type [description] ):
+ * {
+ * "peers": Parcelable[](PeerInfo[]) [ethereum peers]
+ * }
+ */
+ protected void getPeers(Message message) {
+
+ Set peers = ethereum.getPeers();
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_PEERS, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ org.ethereum.android.interop.PeerInfo[] convertedPeers = new org.ethereum.android.interop.PeerInfo[peers.size()];
+ int index = 0;
+ for (PeerInfo peerInfo: peers) {
+ convertedPeers[index] = new org.ethereum.android.interop.PeerInfo(peerInfo);
+ index++;
+ }
+ replyData.putParcelableArray("peers", convertedPeers);
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent peers to client: " + peers.size());
+ } catch (RemoteException e) {
+ logger.error("Exception sending peers to client: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Starts ethereum peer discovery
+ * Incoming message parameters: none
+ * Sends message: none
+ */
+ protected void startPeerDiscovery(Message message) {
+
+ ethereum.startPeerDiscovery();
+ logger.info("Started peer discovery.");
+ }
+
+ /**
+ * Stops ethereum peer discovery
+ * Incoming message parameters: none
+ * Sends message: none
+ */
+ protected void stopPeerDiscovery(Message message) {
+
+ ethereum.stopPeerDiscovery();
+ logger.info("Stopped peer discovery.");
+ }
+
+ /**
+ * Gets the blockchain status
+ *
+ * Incoming message parameters: none
+ * Sends message ( "key": type [description] ):
+ * {
+ * "status": String [blockchain status: Loading/Loaded]
+ * }
+ */
+ protected void getBlockchainStatus(Message message) {
+
+ boolean isLoading = ethereum.isBlockchainLoading();
+ String status = isLoading ? "Loading" : "Loaded";
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_BLOCKCHAIN_STATUS, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ replyData.putString("status", status);
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent blockchain status: " + status);
+ } catch (RemoteException e) {
+ logger.error("Exception sending blockchain status to client: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Add ethereum event listener
+ *
+ * Incoming message parameters: none
+ * Sends message: none
+ */
+ protected void addListener(Message message) {
+
+ // Register the client's messenger
+ clientListeners.add(message.replyTo);
+ // TODO: Add channel listener types flags
+ logger.info("Client listener registered!");
+ }
+
+ /**
+ * Closes ethereum
+ *
+ * Incoming message parameters: none
+ * Sends message: none
+ */
+ protected void closeEthereum(Message message) {
+
+ ethereum.close();
+ logger.info("Closed ethereum.");
+ }
+
+ /**
+ * Get connection status
+ *
+ * Incoming message parameters: none
+ * Sends message ( "key": type [description] ):
+ * {
+ * "status": String [ethereum connection status: Connected/Not Connected]
+ * }
+ */
+ protected void getConnectionStatus(Message message) {
+
+ String status = ethereum.isConnected() ? "Connected" : "Not Connected";
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_CONNECTION_STATUS, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ replyData.putString("status", status);
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent ethereum connection status: " + status);
+ } catch (RemoteException e) {
+ logger.error("Exception sending ethereum connection status to client: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Submit ethereum transaction
+ *
+ * Incoming message parameters ( "key": type [description] ):
+ * {
+ * "transaction": Parcelable(Transaction) [ethereum transaction to submit]
+ * }
+ * Sends message ( "key": type [description] ):
+ * {
+ * "transaction": Parcelable(Transaction) [submitted transaction]
+ * }
+ */
+ protected void submitTransaction(Message message) {
+
+ if (!isConnected) {
+ isConnected = true;
+ new SubmitTransactionTask(message).execute(ethereum);
+ } else {
+ logger.warn("Ethereum not connected.");
+ }
+ }
+
+ protected class SubmitTransactionTask extends AsyncTask {
+
+ Transaction transaction;
+ Message message;
+
+ public SubmitTransactionTask(Message message) {
+
+ this.message = message;
+ Bundle data = message.getData();
+ transaction = data.getParcelable("transaction");
+ }
+
+ protected Transaction doInBackground(Ethereum... args) {
+
+ Transaction submitedTransaction = null;
+ try {
+ submitedTransaction = ethereum.submitTransaction(transaction).get(CONFIG.transactionApproveTimeout(), TimeUnit.SECONDS);
+ logger.info("Submitted transaction.");
+ } catch (Exception e) {
+ logger.error("Exception submitting transaction: " + e.getMessage());
+ }
+
+ return submitedTransaction;
+ }
+
+ protected void onPostExecute(Transaction submittedTransaction) {
+
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_SUBMIT_TRANSACTION_RESULT, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ replyData.putParcelable("transaction", new org.ethereum.android.interop.Transaction(submittedTransaction));
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent submitted transaction: " + submittedTransaction.toString());
+ } catch (RemoteException e) {
+ logger.error("Exception sending submitted transaction to client: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Get admin info
+ *
+ * Incoming message parameters: none
+ * Sends message ( "key": type [description] ):
+ * {
+ * "adminInfo": Parcelable(AdminInfo) [ethereum admin info]
+ * }
+ */
+ protected void getAdminInfo(Message message) {
+
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_ADMIN_INFO, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ AdminInfo info = ethereum.getAdminInfo();
+ replyData.putParcelable("adminInfo", new org.ethereum.android.interop.AdminInfo(info));
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent admin info: " + info.toString());
+ } catch (RemoteException e) {
+ logger.error("Exception sending admin info to client: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Get pending transactions
+ *
+ * Incoming message parameters: none
+ * Sends message ( "key": type [description] ):
+ * {
+ * "transactions": ParcelableArray(Transaction[]) [ethereum pending transactions]
+ * }
+ */
+ protected void getPendingTransactions(Message message) {
+
+ Message replyMessage = Message.obtain(null, EthereumClientMessage.MSG_PENDING_TRANSACTIONS, 0, 0, message.obj);
+ Bundle replyData = new Bundle();
+ Set transactions = ethereum.getPendingTransactions();
+ org.ethereum.android.interop.Transaction[] convertedTransactions = new org.ethereum.android.interop.Transaction[transactions.size()];
+ int index = 0;
+ for (Transaction transaction: transactions) {
+ convertedTransactions[index] = new org.ethereum.android.interop.Transaction(transaction);
+ index++;
+ }
+ replyData.putParcelableArray("transactions", convertedTransactions);
+ replyMessage.setData(replyData);
+ try {
+ message.replyTo.send(replyMessage);
+ logger.info("Sent pending transactions: " + transactions.size());
+ } catch (RemoteException e) {
+ logger.error("Exception sending pending transactions to client: " + e.getMessage());
+ }
+ }
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumAidlService.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumService.java
similarity index 60%
rename from ethereumj-core-android/src/main/java/org/ethereum/android/EthereumAidlService.java
rename to ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumService.java
index 777d3edc..05e78e3c 100644
--- a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumAidlService.java
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumService.java
@@ -1,52 +1,37 @@
-package org.ethereum.android;
+package org.ethereum.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
-import android.os.RemoteException;
import org.ethereum.android.di.components.DaggerEthereumComponent;
import org.ethereum.android.di.modules.EthereumModule;
+import org.ethereum.android.interop.IListener;
import org.ethereum.android.jsonrpc.JsonRpcServer;
-import org.ethereum.android.manager.BlockLoader;
import org.ethereum.config.SystemProperties;
-import org.ethereum.core.*;
+import org.ethereum.core.Transaction;
+import org.ethereum.core.TransactionReceipt;
import org.ethereum.facade.Ethereum;
-import org.ethereum.android.interop.*;
import org.ethereum.net.p2p.HelloMessage;
-import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-public class EthereumAidlService extends Service {
-
- protected Ethereum ethereum = null;
-
- protected JsonRpcServer jsonRpcServer;
-
- protected ArrayList clientListeners = new ArrayList<>();
-
- public static String log = "";
+public class EthereumService extends Service {
boolean isConnected = false;
boolean isInitialized = false;
- public EthereumAidlService() {
+ protected Ethereum ethereum = null;
+
+ protected JsonRpcServer jsonRpcServer;
+
+ public EthereumService() {
}
protected void broadcastMessage(String message) {
- for (IListener listener: clientListeners) {
- try {
- listener.trace(message);
- } catch (Exception e) {
- // Remove listener
- System.out.println("ERRORRRR: " + e.getMessage());
- clientListeners.remove(listener);
- }
- }
}
@Override
@@ -85,56 +70,10 @@ public class EthereumAidlService extends Service {
@Override
public IBinder onBind(Intent intent) {
-
- return mBinder;
+ // TODO: Return the communication channel to the service.
+ throw new UnsupportedOperationException("Not yet implemented");
}
- IEthereumService.Stub mBinder = new IEthereumService.Stub() {
-
- public void loadBlocks(String dumpFile) throws RemoteException {
-
- BlockLoader blockLoader = (BlockLoader)ethereum.getBlockLoader();
- blockLoader.loadBlocks(dumpFile);
- }
-
- public void connect(String ip, int port, String remoteId) throws RemoteException {
-
- if (!isConnected) {
- System.out.println("Connecting to : " + ip);
- ethereum.connect(ip, port, remoteId);
- isConnected = true;
- } else {
- System.out.println("Already connected");
- System.out.println("x " + ethereum.isConnected());
- }
- }
-
- public void addListener(IListener listener) throws RemoteException {
-
- clientListeners.clear();
- clientListeners.add(listener);
- }
-
- public void removeListener(IListener listener) throws RemoteException {
-
- try {
- clientListeners.remove(listener);
- } catch (Exception e) {
- System.out.println("ERRORRRR: " + e.getMessage());
- }
- }
-
- public void startJsonRpcServer() throws RemoteException {
-
- jsonRpcServer = new JsonRpcServer(ethereum);
- }
-
- public void getLog(IAsyncCallback callback) throws RemoteException {
-
- callback.handleResponse(EthereumAidlService.log);
- }
- };
-
protected class EthereumListener implements org.ethereum.listener.EthereumListener {
@Override
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumServiceMessage.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumServiceMessage.java
new file mode 100644
index 00000000..214b8862
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/EthereumServiceMessage.java
@@ -0,0 +1,76 @@
+package org.ethereum.android.service;
+
+
+public class EthereumServiceMessage {
+
+ /**
+ * Command to the service to connect to a peer
+ */
+ public static final int MSG_CONNECT = 1;
+
+ /**
+ * Command to the service to load blocks dumpr
+ */
+ public static final int MSG_LOAD_BLOCKS = 2;
+
+ /**
+ * Command to the service to start json rpc server
+ */
+ public static final int MSG_START_JSON_RPC_SERVER = 3;
+
+ /**
+ * Command to the service to find an online peer
+ */
+ public static final int MSG_FIND_ONLINE_PEER = 4;
+
+ /**
+ * Command to the service to list the peers
+ */
+ public static final int MSG_GET_PEERS = 5;
+
+ /**
+ * Command to the service to start peer discovery
+ */
+ public static final int MSG_START_PEER_DISCOVERY = 6;
+
+ /**
+ * Command to the service to stop peer discovery
+ */
+ public static final int MSG_STOP_PEER_DISCOVERY = 7;
+
+ /**
+ * Command to the service to get blockchain status (Loading/Loaded)
+ */
+ public static final int MSG_GET_BLOCKCHAIN_STATUS = 8;
+
+ /**
+ * Command to the service to add a listener
+ *
+ */
+ public static final int MSG_ADD_LISTENER = 9;
+
+ /**
+ * Command to the service to get connection status (Connected/Not Connected)
+ */
+ public static final int MSG_GET_CONNECTION_STATUS = 10;
+
+ /**
+ * Command to the service to close
+ */
+ public static final int MSG_CLOSE = 11;
+
+ /**
+ * Command to the service to submit a transaction
+ */
+ public static final int MSG_SUBMIT_TRANSACTION = 12;
+
+ /**
+ * Command to the service to get the admin info
+ */
+ public static final int MSG_GET_ADMIN_INFO = 13;
+
+ /**
+ * Command to the service to get the pernding transactions
+ */
+ public static final int MSG_GET_PENDING_TRANSACTIONS = 14;
+}
diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/service/ServiceConnector.java b/ethereumj-core-android/src/main/java/org/ethereum/android/service/ServiceConnector.java
new file mode 100644
index 00000000..383a8694
--- /dev/null
+++ b/ethereumj-core-android/src/main/java/org/ethereum/android/service/ServiceConnector.java
@@ -0,0 +1,140 @@
+package org.ethereum.android.service;
+
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+
+import java.util.ArrayList;
+
+public class ServiceConnector {
+
+ /**
+ * Incoming message handler. Calls to its binder are sequential!
+ */
+ protected final IncomingHandler handler;
+
+ /**
+ * Handler thread to avoid running on the main UI thread
+ */
+ protected final HandlerThread handlerThread;
+
+ /** Context of the activity from which this connector was launched */
+ protected Context context;
+
+ /** The class of the service we want to connect to */
+ protected Class serviceClass;
+
+ /** Flag indicating if the service is bound. */
+ boolean isBound;
+
+ /** Sends messages to the service. */
+ Messenger serviceMessenger = null;
+
+ /** Receives messages from the service. */
+ Messenger clientMessenger = null;
+
+ ArrayList handlers = new ArrayList<>();
+
+ /** Handles incoming messages from service. */
+ class IncomingHandler extends Handler {
+
+ public IncomingHandler(HandlerThread thread) {
+
+ super(thread.getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+
+ boolean isClaimed = false;
+ String identifier = ((Bundle)message.obj).getString("identifier");
+ if (identifier != null) {
+
+ for (ConnectorHandler handler : handlers) {
+ if (identifier.equals(handler.getID())) {
+ isClaimed = handler.handleMessage(message);
+ }
+ }
+ }
+ if (!isClaimed) {
+ super.handleMessage(message);
+ }
+ }
+ }
+
+ /**
+ * Class for interacting with the main interface of the service.
+ */
+ protected ServiceConnection serviceConnection = null;
+
+ public ServiceConnector(Context context, Class serviceClass) {
+
+ this.context = context;
+ this.serviceClass = serviceClass;
+ handlerThread = new HandlerThread("HandlerThread");
+ handlerThread.start();
+ handler = new IncomingHandler(handlerThread);
+ clientMessenger = new Messenger(handler);
+ initializeServiceConnection();
+ }
+
+ protected void initializeServiceConnection() {
+
+ serviceConnection = new ServiceConnection() {
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+
+ // This is called when the connection with the service has been
+ // established, giving us the object we can use to
+ // interact with the service. We are communicating with the
+ // service using a Messenger, so here we get a client-side
+ // representation of that from the raw IBinder object.
+ serviceMessenger = new Messenger(service);
+ isBound = true;
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+
+ // This is called when the connection with the service has been
+ // unexpectedly disconnected -- that is, its process crashed.
+ serviceMessenger = null;
+ isBound = false;
+ }
+ };
+ }
+
+ /** Bind to the service */
+ public boolean bindService() {
+
+ if (serviceConnection != null) {
+ Intent intent = new Intent(context, serviceClass);
+ return context.getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+ } else {
+ return false;
+ }
+ }
+
+ /** Unbind from the service */
+ public void unbindService() {
+
+ if (isBound && serviceConnection != null) {
+ context.getApplicationContext().unbindService(serviceConnection);
+ isBound = false;
+ }
+ }
+
+ public void registerHandler(ConnectorHandler handler) {
+
+ handlers.add(handler);
+ }
+
+}
diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java b/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java
index af215ef2..deb5d85a 100644
--- a/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java
+++ b/ethereumj-core/src/main/java/org/ethereum/manager/AdminInfo.java
@@ -14,9 +14,9 @@ import javax.inject.Singleton;
public class AdminInfo {
- private long startupTimeStamp;
- private boolean consensus = true;
- private List blockExecTime = new LinkedList<>();
+ protected long startupTimeStamp;
+ protected boolean consensus = true;
+ protected List blockExecTime = new LinkedList<>();
public AdminInfo() {
this.init();
diff --git a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/PeerInfo.java b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/PeerInfo.java
index b260d709..3c92a2fb 100644
--- a/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/PeerInfo.java
+++ b/ethereumj-core/src/main/java/org/ethereum/net/peerdiscovery/PeerInfo.java
@@ -14,9 +14,9 @@ import java.util.List;
*/
public class PeerInfo {
- private InetAddress address;
- private int port;
- private String peerId;
+ protected InetAddress address;
+ protected int port;
+ protected String peerId;
private List capabilities;
private HelloMessage handshakeHelloMessage;