From 1e59d8ec407a72baea4080e176f72dc671c72c60 Mon Sep 17 00:00:00 2001 From: "Nelson R. Perez" Date: Wed, 4 Apr 2018 21:07:09 -0500 Subject: [PATCH] Handling only credentials and API access messages locally, deferring all other messages to the bus --- graphenej/build.gradle | 31 ++-- .../cy/agorise/graphenej/api/ApiAccess.java | 11 ++ .../graphenej/api/bitshares/Nodes.java | 1 - .../graphenej/api/calls/ApiCallable.java | 17 ++ .../agorise/graphenej/api/calls/GetBlock.java | 27 +++ .../cy/agorise/graphenej/models/ApiCall.java | 52 +++--- .../graphenej/models/BaseResponse.java | 4 +- .../graphenej/models/JsonRpcResponse.java | 31 ++++ .../graphenej/models/WitnessResponse.java | 1 + sample/build.gradle | 1 - .../luminiasoft/labs/sample/MainActivity.java | 39 ++++- .../labs/sample/NetworkService.java | 154 +++++++++++++++++- .../labs/sample/SampleApplication.java | 4 + .../labs/sample/SecondActivity.java | 47 ++++++ 14 files changed, 363 insertions(+), 57 deletions(-) create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/api/ApiAccess.java create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/api/calls/ApiCallable.java create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetBlock.java create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/models/JsonRpcResponse.java diff --git a/graphenej/build.gradle b/graphenej/build.gradle index 85c6653..7854e9b 100644 --- a/graphenej/build.gradle +++ b/graphenej/build.gradle @@ -5,21 +5,6 @@ apply plugin: 'com.android.library' apply from: 'maven-push.gradle' -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.12' - compile 'com.neovisionaries:nv-websocket-client:1.30' - compile 'org.bitcoinj:bitcoinj-core:0.14.3' - compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' - compile group: "org.tukaani", name: "xz", version: "1.6" - - // Rx dependencies - compile 'io.reactivex.rxjava2:rxandroid:2.0.2' - compile 'io.reactivex.rxjava2:rxjava:2.1.9' - compile 'com.jakewharton.rxrelay2:rxrelay:2.0.0' - compile 'com.squareup.okhttp3:okhttp:3.5.0' -} - - android { compileSdkVersion 24 buildToolsVersion "25.0.0" @@ -37,4 +22,18 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } -} \ No newline at end of file +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' + compile 'com.neovisionaries:nv-websocket-client:1.30' + compile 'org.bitcoinj:bitcoinj-core:0.14.3' + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0' + compile group: "org.tukaani", name: "xz", version: "1.6" + + // Rx dependencies + compile 'io.reactivex.rxjava2:rxandroid:2.0.2' + compile 'io.reactivex.rxjava2:rxjava:2.1.9' + compile 'com.jakewharton.rxrelay2:rxrelay:2.0.0' + compile 'com.squareup.okhttp3:okhttp:3.5.0' +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/ApiAccess.java b/graphenej/src/main/java/cy/agorise/graphenej/api/ApiAccess.java new file mode 100644 index 0000000..981bc02 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/ApiAccess.java @@ -0,0 +1,11 @@ +package cy.agorise.graphenej.api; + +/** + * Class used to list all currently supported API accesses + */ + +public class ApiAccess { + public static final int API_DATABASE = 0x01; + public static final int API_HISTORY = 0x02; + public static final int API_NETWORK_BROADCAST = 0x04; +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/bitshares/Nodes.java b/graphenej/src/main/java/cy/agorise/graphenej/api/bitshares/Nodes.java index 8fdc8d2..eabb0c5 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/api/bitshares/Nodes.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/bitshares/Nodes.java @@ -7,7 +7,6 @@ package cy.agorise.graphenej.api.bitshares; public class Nodes { public static final String[] NODE_URLS = { "wss://bitshares.nus/ws", - "ws://echo.websocket.org", "wss://dexnode.net/ws", // Dallas, USA "wss://bitshares.crypto.fans/ws", // Munich, Germany "wss://bitshares.openledger.info/ws", // Openledger node diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/calls/ApiCallable.java b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/ApiCallable.java new file mode 100644 index 0000000..32ebecb --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/ApiCallable.java @@ -0,0 +1,17 @@ +package cy.agorise.graphenej.api.calls; + +import cy.agorise.graphenej.models.ApiCall; + +/** + * Interface to be implemented by all classes that will produce an ApiCall object instance + * as a result. + */ + +public interface ApiCallable { + + /** + * + * @return An instance of the {@link ApiCall} class + */ + ApiCall toApiCall(int apiId, long sequenceId); +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetBlock.java b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetBlock.java new file mode 100644 index 0000000..f38c298 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetBlock.java @@ -0,0 +1,27 @@ +package cy.agorise.graphenej.api.calls; + +import java.io.Serializable; +import java.util.ArrayList; + +import cy.agorise.graphenej.RPC; +import cy.agorise.graphenej.models.ApiCall; + +/** + * Wrapper aroung the "get_block" API call. + */ + +public class GetBlock implements ApiCallable { + + private long blockNumber; + + public GetBlock(int blockNum){ + this.blockNumber = blockNum; + } + + public ApiCall toApiCall(int apiId, long sequenceId){ + ArrayList params = new ArrayList<>(); + String blockNum = String.format("%d", this.blockNumber); + params.add(blockNum); + return new ApiCall(apiId, RPC.CALL_GET_BLOCK, params, RPC.VERSION, sequenceId); + } +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/models/ApiCall.java b/graphenej/src/main/java/cy/agorise/graphenej/models/ApiCall.java index 58707ae..92de59b 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/models/ApiCall.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/models/ApiCall.java @@ -66,33 +66,35 @@ public class ApiCall implements JsonSerializable { paramsArray.add(this.methodToCall); JsonArray methodParams = new JsonArray(); - for(int i = 0; i < this.params.size(); i++){ - if(this.params.get(i) instanceof JsonSerializable) { - // Sometimes the parameters are objects - methodParams.add(((JsonSerializable) this.params.get(i)).toJsonObject()); - }else if (Number.class.isInstance(this.params.get(i))){ - // Other times they are numbers - methodParams.add( (Number) this.params.get(i)); - }else if(this.params.get(i) instanceof String || this.params.get(i) == null){ - // Other times they are plain strings - methodParams.add((String) this.params.get(i)); - }else if(this.params.get(i) instanceof ArrayList) { - // Other times it might be an array - JsonArray array = new JsonArray(); - ArrayList listArgument = (ArrayList) this.params.get(i); - for (int l = 0; l < listArgument.size(); l++) { - Serializable element = listArgument.get(l); - if (element instanceof JsonSerializable) - array.add(((JsonSerializable) element).toJsonObject()); - else if (element instanceof String) { - array.add((String) element); + if(this.params != null){ + for(int i = 0; i < this.params.size(); i++){ + if(this.params.get(i) instanceof JsonSerializable) { + // Sometimes the parameters are objects + methodParams.add(((JsonSerializable) this.params.get(i)).toJsonObject()); + }else if (Number.class.isInstance(this.params.get(i))){ + // Other times they are numbers + methodParams.add( (Number) this.params.get(i)); + }else if(this.params.get(i) instanceof String || this.params.get(i) == null){ + // Other times they are plain strings + methodParams.add((String) this.params.get(i)); + }else if(this.params.get(i) instanceof ArrayList) { + // Other times it might be an array + JsonArray array = new JsonArray(); + ArrayList listArgument = (ArrayList) this.params.get(i); + for (int l = 0; l < listArgument.size(); l++) { + Serializable element = listArgument.get(l); + if (element instanceof JsonSerializable) + array.add(((JsonSerializable) element).toJsonObject()); + else if (element instanceof String) { + array.add((String) element); + } } + methodParams.add(array); + }else if(this.params.get(i) instanceof Boolean){ + methodParams.add((boolean) this.params.get(i)); + }else{ + System.out.println("Skipping parameter of type: "+this.params.get(i).getClass()); } - methodParams.add(array); - }else if(this.params.get(i) instanceof Boolean){ - methodParams.add((boolean) this.params.get(i)); - }else{ - System.out.println("Skipping parameter of type: "+this.params.get(i).getClass()); } } paramsArray.add(methodParams); diff --git a/graphenej/src/main/java/cy/agorise/graphenej/models/BaseResponse.java b/graphenej/src/main/java/cy/agorise/graphenej/models/BaseResponse.java index 50b7622..398aac5 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/models/BaseResponse.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/models/BaseResponse.java @@ -1,11 +1,13 @@ package cy.agorise.graphenej.models; /** - * Created by nelson on 11/12/16. + * Base response class + * @deprecated Use {@link JsonRpcResponse} instead */ public class BaseResponse { public long id; public Error error; + public Object result; public static class Error { public ErrorData data; diff --git a/graphenej/src/main/java/cy/agorise/graphenej/models/JsonRpcResponse.java b/graphenej/src/main/java/cy/agorise/graphenej/models/JsonRpcResponse.java new file mode 100644 index 0000000..00d216b --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/models/JsonRpcResponse.java @@ -0,0 +1,31 @@ +package cy.agorise.graphenej.models; + +/** + * Used to represent a JSON-RPC response object + */ + +public class JsonRpcResponse { + public long id; + public Error error; + public T result; + + public static class Error { + public ErrorData data; + public int code; + public String message; + public Error(String message){ + this.message = message; + } + } + + public static class ErrorData { + public int code; + public String name; + public String message; + //TODO: Include stack data + + public ErrorData(String message){ + this.message = message; + } + } +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/models/WitnessResponse.java b/graphenej/src/main/java/cy/agorise/graphenej/models/WitnessResponse.java index 2cabae9..e6f3ffc 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/models/WitnessResponse.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/models/WitnessResponse.java @@ -2,6 +2,7 @@ package cy.agorise.graphenej.models; /** * Generic witness response + * @deprecated Use {@link JsonRpcResponse} instead */ public class WitnessResponse extends BaseResponse{ public static final String KEY_ID = "id"; diff --git a/sample/build.gradle b/sample/build.gradle index 6364279..1eb0030 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -22,7 +22,6 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - } dependencies { diff --git a/sample/src/main/java/com/luminiasoft/labs/sample/MainActivity.java b/sample/src/main/java/com/luminiasoft/labs/sample/MainActivity.java index 11b831f..464b1f0 100644 --- a/sample/src/main/java/com/luminiasoft/labs/sample/MainActivity.java +++ b/sample/src/main/java/com/luminiasoft/labs/sample/MainActivity.java @@ -6,16 +6,22 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; +import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.TextView; +import com.google.gson.Gson; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import cy.agorise.graphenej.api.ApiAccess; import cy.agorise.graphenej.api.ConnectionStatusUpdate; import cy.agorise.graphenej.api.android.RxBus; +import cy.agorise.graphenej.api.calls.GetBlock; +import cy.agorise.graphenej.models.JsonRpcResponse; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Consumer; @@ -31,25 +37,39 @@ public class MainActivity extends AppCompatActivity { // In case we want to interact directly with the service private NetworkService mService; + private Gson gson = new Gson(); + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); + // Specifying some important information regarding the connection, such as the + // credentials and the requested API accesses + int requestedApis = ApiAccess.API_DATABASE | ApiAccess.API_HISTORY | ApiAccess.API_NETWORK_BROADCAST; + PreferenceManager.getDefaultSharedPreferences(this) + .edit() + .putString(NetworkService.KEY_USERNAME, "nelson") + .putString(NetworkService.KEY_PASSWORD, "secret") + .putInt(NetworkService.KEY_REQUESTED_APIS, requestedApis) + .apply(); + RxBus.getBusInstance() .asFlowable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer() { @Override - public void accept(Object o) throws Exception { - if(o instanceof String){ - Log.d(TAG,"Got message"); - mResponse.setText(mResponse.getText() + ((String)o) + "\n"); - }else if(o instanceof ConnectionStatusUpdate){ - Log.d(TAG,"Got connection update"); - mConnectionStatus.setText(((ConnectionStatusUpdate)o).getConnectionStatus()); + public void accept(Object message) throws Exception { + if(message instanceof String){ + Log.d(TAG,"Got text message: "+(message)); + mResponse.setText(mResponse.getText() + ((String) message) + "\n"); + }else if(message instanceof ConnectionStatusUpdate){ + Log.d(TAG,"Got connection update. Status: "+((ConnectionStatusUpdate)message).getConnectionStatus()); + mConnectionStatus.setText(((ConnectionStatusUpdate) message).getConnectionStatus()); + }else if(message instanceof JsonRpcResponse){ + mResponse.setText(mResponse.getText() + gson.toJson(message, JsonRpcResponse.class) + "\n"); } } }); @@ -57,7 +77,8 @@ public class MainActivity extends AppCompatActivity { @OnClick(R.id.send_message) public void onSendMesage(View v){ - mService.sendMessage("Sample message"); + GetBlock getBlock = new GetBlock(1000000); + mService.sendMessage(getBlock); } @OnClick(R.id.next_activity) @@ -71,6 +92,8 @@ public class MainActivity extends AppCompatActivity { super.onStart(); // Bind to LocalService Intent intent = new Intent(this, NetworkService.class); + int requestedApis = ApiAccess.API_DATABASE | ApiAccess.API_HISTORY | ApiAccess.API_NETWORK_BROADCAST; + intent.putExtra(NetworkService.KEY_REQUESTED_APIS, requestedApis); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } diff --git a/sample/src/main/java/com/luminiasoft/labs/sample/NetworkService.java b/sample/src/main/java/com/luminiasoft/labs/sample/NetworkService.java index 15fa515..473c861 100644 --- a/sample/src/main/java/com/luminiasoft/labs/sample/NetworkService.java +++ b/sample/src/main/java/com/luminiasoft/labs/sample/NetworkService.java @@ -2,14 +2,29 @@ package com.luminiasoft.labs.sample; import android.app.Service; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Binder; import android.os.IBinder; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.util.Log; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; + +import cy.agorise.graphenej.RPC; +import cy.agorise.graphenej.api.ApiAccess; import cy.agorise.graphenej.api.ConnectionStatusUpdate; import cy.agorise.graphenej.api.android.RxBus; import cy.agorise.graphenej.api.bitshares.Nodes; +import cy.agorise.graphenej.api.calls.ApiCallable; +import cy.agorise.graphenej.models.ApiCall; +import cy.agorise.graphenej.models.JsonRpcResponse; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -25,12 +40,35 @@ public class NetworkService extends Service { private static final int NORMAL_CLOSURE_STATUS = 1000; + public static final String KEY_USERNAME = "key_username"; + + public static final String KEY_PASSWORD = "key_password"; + + public static final String KEY_REQUESTED_APIS = "key_requested_apis"; + private final IBinder mBinder = new LocalBinder(); private WebSocket mWebSocket; private int mSocketIndex; + // Username and password used to connect to a specific node + private String mUsername; + private String mPassword; + + private boolean isLoggedIn = false; + + private String mLastCall; + private int mCurrentId = 0; + + // Requested APIs passed to this service + private int mRequestedApis; + + // Variable used to keep track of the currently obtained API accesses + private HashMap mApiIds = new HashMap(); + + private Gson gson = new Gson(); + private WebSocketListener mWebSocketListener = new WebSocketListener() { @Override @@ -38,13 +76,92 @@ public class NetworkService extends Service { super.onOpen(webSocket, response); mWebSocket = webSocket; RxBus.getBusInstance().send(new ConnectionStatusUpdate(ConnectionStatusUpdate.CONNECTED)); + + if(!isLoggedIn){ + Log.d(TAG,"About to send login request"); + ArrayList loginParams = new ArrayList<>(); + loginParams.add(mUsername); + loginParams.add(mPassword); + ApiCall loginCall = new ApiCall(1, RPC.CALL_LOGIN, loginParams, RPC.VERSION, ++mCurrentId); + mLastCall = RPC.CALL_LOGIN; + sendMessage(loginCall.toJsonString()); + }else{ + Log.d(TAG,"Already logged in"); + } } @Override public void onMessage(WebSocket webSocket, String text) { super.onMessage(webSocket, text); - Log.d(TAG,"onMessage. text: "+text); - RxBus.getBusInstance().send(text); + Log.v(TAG,"< "+text); + JsonRpcResponse response = gson.fromJson(text, JsonRpcResponse.class); + + // We will only handle messages that relate to the login and API accesses here. + if(response.result != null){ + if(mLastCall == RPC.CALL_LOGIN){ + isLoggedIn = true; + + checkNextRequestedApiAccess(); + }else if(mLastCall == RPC.CALL_DATABASE){ + // Deserializing integer response + Type IntegerJsonResponse = new TypeToken>(){}.getType(); + JsonRpcResponse apiIdResponse = gson.fromJson(text, IntegerJsonResponse); + + // Storing the "database" api id + mApiIds.put(ApiAccess.API_DATABASE, apiIdResponse.result); + + checkNextRequestedApiAccess(); + }else if(mLastCall == RPC.CALL_HISTORY){ + // Deserializing integer response + Type IntegerJsonResponse = new TypeToken>(){}.getType(); + JsonRpcResponse apiIdResponse = gson.fromJson(text, IntegerJsonResponse); + + // Storing the "history" api id + mApiIds.put(ApiAccess.API_HISTORY, apiIdResponse.result); + + checkNextRequestedApiAccess(); + }else if(mLastCall == RPC.CALL_NETWORK_BROADCAST){ + // Deserializing integer response + Type IntegerJsonResponse = new TypeToken>(){}.getType(); + JsonRpcResponse apiIdResponse = gson.fromJson(text, IntegerJsonResponse); + + // Storing the "network_broadcast" api access + mApiIds.put(ApiAccess.API_NETWORK_BROADCAST, apiIdResponse.result); + + // All calls have been handled at this point + mLastCall = ""; + }else{ + Log.d(TAG,"New unhandled message"); + } + }else{ + Log.w(TAG,"Error.Msg: "+response.error.message); + } + RxBus.getBusInstance().send(response); + } + + private void checkNextRequestedApiAccess(){ + if( (mRequestedApis & ApiAccess.API_DATABASE) == ApiAccess.API_DATABASE && + mApiIds.get(ApiAccess.API_DATABASE) == null){ + // If we need the "database" api access and we don't yet have it + + ApiCall apiCall = new ApiCall(1, RPC.CALL_DATABASE, null, RPC.VERSION, ++mCurrentId); + mLastCall = RPC.CALL_DATABASE; + sendMessage(apiCall.toJsonString()); + } else if( (mRequestedApis & ApiAccess.API_HISTORY) == ApiAccess.API_HISTORY && + mApiIds.get(ApiAccess.API_HISTORY) == null){ + // If we need the "history" api access and we don't yet have it + + ApiCall apiCall = new ApiCall(1, RPC.CALL_HISTORY, null, RPC.VERSION, ++mCurrentId); + mLastCall = RPC.CALL_HISTORY; + sendMessage(apiCall.toJsonString()); + }else if( (mRequestedApis & ApiAccess.API_NETWORK_BROADCAST) == ApiAccess.API_NETWORK_BROADCAST && + mApiIds.get(ApiAccess.API_NETWORK_BROADCAST) == null){ + // If we need the "network_broadcast" api access and we don't yet have it + + ApiCall apiCall = new ApiCall(1, RPC.CALL_NETWORK_BROADCAST, null, RPC.VERSION, ++mCurrentId); + mLastCall = RPC.CALL_NETWORK_BROADCAST; + sendMessage(apiCall.toJsonString()); + } } @Override @@ -52,12 +169,21 @@ public class NetworkService extends Service { super.onClosed(webSocket, code, reason); Log.d(TAG,"onClosed"); RxBus.getBusInstance().send(new ConnectionStatusUpdate(ConnectionStatusUpdate.DISCONNECTED)); + + isLoggedIn = false; } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { super.onFailure(webSocket, t, response); - Log.d(TAG,"onFailure. Msg: "+t.getMessage()); + Log.e(TAG,"onFailure. Msg: "+t.getMessage()); + isLoggedIn = false; + if(response != null){ + Log.e(TAG,"Response: "+response.message()); + } + for(StackTraceElement element : t.getStackTrace()){ + Log.v(TAG,String.format("%s#%s:%d", element.getClassName(), element.getMethodName(), element.getLineNumber())); + } RxBus.getBusInstance().send(new ConnectionStatusUpdate(ConnectionStatusUpdate.DISCONNECTED)); mSocketIndex++; connect(); @@ -68,24 +194,42 @@ public class NetworkService extends Service { public void onCreate() { super.onCreate(); Log.d(TAG,"onCreate"); + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + // Retrieving credentials and requested API data from the shared preferences + mUsername = pref.getString(NetworkService.KEY_USERNAME, ""); + mPassword = pref.getString(NetworkService.KEY_PASSWORD, ""); + mRequestedApis = pref.getInt(NetworkService.KEY_REQUESTED_APIS, -1); + connect(); } private void connect(){ OkHttpClient client = new OkHttpClient(); String url = Nodes.NODE_URLS[mSocketIndex % Nodes.NODE_URLS.length]; + Log.d(TAG,"Trying to connect with: "+url); Request request = new Request.Builder().url(url).build(); client.newWebSocket(request, mWebSocketListener); } - public void sendMessage(String message){ + public int sendMessage(String message){ if(mWebSocket.send(message)){ - Log.d(TAG,"Message enqueued"); + Log.v(TAG,"> " + message); }else{ Log.w(TAG,"Message not enqueued"); } + return mCurrentId; } + public int sendMessage(ApiCallable apiCallable){ + ApiCall call = apiCallable.toApiCall(mApiIds.get(ApiAccess.API_DATABASE), mCurrentId); + if(mWebSocket.send(call.toJsonString())){ + Log.v(TAG,"> "+call.toJsonString()); + }else{ + Log.w(TAG,"Message not enqueued"); + } + return mCurrentId; + } @Override public void onDestroy() { diff --git a/sample/src/main/java/com/luminiasoft/labs/sample/SampleApplication.java b/sample/src/main/java/com/luminiasoft/labs/sample/SampleApplication.java index 2459212..124c7cd 100644 --- a/sample/src/main/java/com/luminiasoft/labs/sample/SampleApplication.java +++ b/sample/src/main/java/com/luminiasoft/labs/sample/SampleApplication.java @@ -7,6 +7,8 @@ import android.os.Bundle; import android.os.Handler; import android.util.Log; +import cy.agorise.graphenej.api.ApiAccess; + /** * Sample application class */ @@ -43,6 +45,8 @@ public class SampleApplication extends Application implements Application.Activi public void onCreate() { super.onCreate(); Intent intent = new Intent(this, NetworkService.class); + int requestedApis = ApiAccess.API_DATABASE | ApiAccess.API_HISTORY | ApiAccess.API_NETWORK_BROADCAST; + intent.putExtra(NetworkService.KEY_REQUESTED_APIS, requestedApis); startService(intent); /* diff --git a/sample/src/main/java/com/luminiasoft/labs/sample/SecondActivity.java b/sample/src/main/java/com/luminiasoft/labs/sample/SecondActivity.java index e16489b..0168653 100644 --- a/sample/src/main/java/com/luminiasoft/labs/sample/SecondActivity.java +++ b/sample/src/main/java/com/luminiasoft/labs/sample/SecondActivity.java @@ -1,13 +1,60 @@ package com.luminiasoft.labs.sample; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.util.Log; + +import cy.agorise.graphenej.api.ApiAccess; public class SecondActivity extends AppCompatActivity { + private final String TAG = this.getClass().getName(); + + // In case we want to interact directly with the service + private NetworkService mService; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); } + + @Override + protected void onStart() { + super.onStart(); + // Bind to LocalService + Intent intent = new Intent(this, NetworkService.class); + int requestedApis = ApiAccess.API_DATABASE | ApiAccess.API_HISTORY | ApiAccess.API_NETWORK_BROADCAST; + intent.putExtra(NetworkService.KEY_REQUESTED_APIS, requestedApis); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onPause() { + super.onPause(); + unbindService(mConnection); + } + + /** Defines callbacks for backend binding, passed to bindService() */ + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + Log.d(TAG,"onServiceConnected"); + // We've bound to LocalService, cast the IBinder and get LocalService instance + NetworkService.LocalBinder binder = (NetworkService.LocalBinder) service; + mService = binder.getService(); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.d(TAG,"onServiceDisconnected"); + } + }; }