Implemented remote service using Messenger.
This commit is contained in:
parent
33be741881
commit
961fb203df
|
@ -14,7 +14,7 @@
|
|||
android:largeHeap="true"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".RemoteMainActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -28,11 +28,22 @@
|
|||
</activity>
|
||||
|
||||
<service
|
||||
android:name="org.ethereum.android_app.EthereumService"
|
||||
android:name=".EthereumService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":ethereum_process" >
|
||||
</service>
|
||||
<service
|
||||
android:name=".EthereumRemoteService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":ethereum_remote_process" >
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name=".AidlMainActivity"
|
||||
android:label="@string/app_name" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package org.ethereum.android_app;
|
||||
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
public interface ActivityInterface {
|
||||
|
||||
void registerFragment(FragmentInterface fragment);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.ethereum.android_app;
|
||||
|
||||
|
||||
public class EthereumRemoteService extends org.ethereum.android.service.EthereumRemoteService {
|
||||
|
||||
public EthereumRemoteService() {
|
||||
|
||||
super();
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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<FragmentInterface> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="org.ethereum.android_app.RemoteMainActivity">
|
||||
|
||||
<TextView android:text="@string/hello_world" android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -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" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/textView2"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:weightSum="1">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Connect"
|
||||
android:id="@+id/connectButton"
|
||||
android:layout_below="@+id/textView2"
|
||||
android:layout_alignLeft="@+id/getBlockchainStatus"
|
||||
android:layout_alignStart="@+id/getBlockchainStatus"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textSize="10sp" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ethereum Status"
|
||||
android:id="@+id/getEthereumStatus"
|
||||
android:layout_alignTop="@+id/connectButton"
|
||||
android:layout_toRightOf="@+id/textView"
|
||||
android:layout_toEndOf="@+id/textView"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:singleLine="true"
|
||||
android:textSize="10sp" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Blockchain Status"
|
||||
android:id="@+id/getBlockchainStatus"
|
||||
android:layout_marginBottom="42dp"
|
||||
android:layout_above="@+id/textView"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:textSize="10sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Ethereum Status: "
|
||||
android:id="@+id/textView" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Not Connected"
|
||||
android:id="@+id/connectionStatus" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Blockchain Status: "
|
||||
android:id="@+id/textView4" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="None"
|
||||
android:id="@+id/blockchainStatus" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Startup Time:"
|
||||
android:id="@+id/textView6" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="None"
|
||||
android:id="@+id/startupTime" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Is Consensus:"
|
||||
android:id="@+id/textView3" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="None"
|
||||
android:id="@+id/isConsensus" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="Average block exec time:"
|
||||
android:id="@+id/textView7" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:text="None"
|
||||
android:id="@+id/blockExecTime" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="org.ethereum.android_app.RemoteMainActivity">
|
||||
<item android:id="@+id/action_settings" android:title="@string/action_settings"
|
||||
android:orderInCategory="100" app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
<string name="title_activity_test">TestActivity</string>
|
||||
|
||||
<string name="hello_world">Hello world!</string>
|
||||
<string name="title_activity_remote_main">RemoteMainActivity</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
android:allowBackup="true"
|
||||
android:label="@string/app_name" >
|
||||
<service
|
||||
android:name=".EthereumAidlService"
|
||||
android:name=".service.EthereumAidlService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":ethereum_process" >
|
||||
|
@ -15,13 +15,13 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".EthereumRemoteService"
|
||||
android:name=".service.EthereumRemoteService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:process=":ethereum_process" >
|
||||
</service>
|
||||
<service
|
||||
android:name=".EthereumService"
|
||||
android:name=".service.EthereumService"
|
||||
android:enabled="true"
|
||||
android:exported="true" >
|
||||
</service>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<!-- Create a logcat appender -->
|
||||
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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<Long> 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<Long> arrayToList(long[] array) {
|
||||
|
||||
ArrayList<Long> list = new ArrayList<>(array.length);
|
||||
for (long item : array) {
|
||||
list.add(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AdminInfo> CREATOR = new Parcelable.Creator<AdminInfo>() {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -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<PeerInfo> CREATOR = new Parcelable.Creator<PeerInfo>() {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Transaction> CREATOR = new Parcelable.Creator<Transaction>() {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.ethereum.android.service;
|
||||
|
||||
|
||||
import android.os.Message;
|
||||
|
||||
public interface ConnectorHandler {
|
||||
|
||||
boolean handleMessage(Message message);
|
||||
String getID();
|
||||
}
|
|
@ -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<IListener> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Messenger> clientListeners = new ArrayList<>();
|
||||
|
||||
public EthereumRemoteService() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
/** Handles incoming messages from clients. */
|
||||
static class IncomingHandler extends Handler {
|
||||
|
||||
private final WeakReference<EthereumRemoteService> service;
|
||||
|
||||
IncomingHandler(EthereumRemoteService service) {
|
||||
|
||||
this.service = new WeakReference<EthereumRemoteService>(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<Ethereum, Message, Void> {
|
||||
|
||||
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<Ethereum, Message, Void> {
|
||||
|
||||
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<PeerInfo> 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<Ethereum, Void, Transaction> {
|
||||
|
||||
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<Transaction> 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<IListener> 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
|
|
@ -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
|
||||
* <Not Implemented>
|
||||
*/
|
||||
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;
|
||||
}
|
|
@ -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<ConnectorHandler> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,9 +14,9 @@ import javax.inject.Singleton;
|
|||
public class AdminInfo {
|
||||
|
||||
|
||||
private long startupTimeStamp;
|
||||
private boolean consensus = true;
|
||||
private List<Long> blockExecTime = new LinkedList<>();
|
||||
protected long startupTimeStamp;
|
||||
protected boolean consensus = true;
|
||||
protected List<Long> blockExecTime = new LinkedList<>();
|
||||
|
||||
public AdminInfo() {
|
||||
this.init();
|
||||
|
|
|
@ -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<Capability> capabilities;
|
||||
private HelloMessage handshakeHelloMessage;
|
||||
|
|
Loading…
Reference in New Issue