diff --git a/graphenej/src/main/java/cy/agorise/graphenej/RPC.java b/graphenej/src/main/java/cy/agorise/graphenej/RPC.java index c0afa8c..028130c 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/RPC.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/RPC.java @@ -14,6 +14,7 @@ public class RPC { public static final String CALL_CANCEL_ALL_SUBSCRIPTIONS = "cancel_all_subscriptions"; public static final String CALL_GET_ACCOUNT_BY_NAME = "get_account_by_name"; public static final String CALL_GET_ACCOUNTS = "get_accounts"; + public static final String CALL_GET_FULL_ACCOUNTS = "get_full_accounts"; public static final String CALL_GET_DYNAMIC_GLOBAL_PROPERTIES = "get_dynamic_global_properties"; public static final String CALL_BROADCAST_TRANSACTION = "broadcast_transaction"; public static final String CALL_GET_REQUIRED_FEES = "get_required_fees"; diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/android/DeserializationMap.java b/graphenej/src/main/java/cy/agorise/graphenej/api/android/DeserializationMap.java index fa4ea68..f7b697b 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/api/android/DeserializationMap.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/android/DeserializationMap.java @@ -23,6 +23,7 @@ import cy.agorise.graphenej.api.calls.GetAccountHistoryByOperations; import cy.agorise.graphenej.api.calls.GetAccounts; import cy.agorise.graphenej.api.calls.GetBlock; import cy.agorise.graphenej.api.calls.GetBlockHeader; +import cy.agorise.graphenej.api.calls.GetFullAccounts; import cy.agorise.graphenej.api.calls.GetLimitOrders; import cy.agorise.graphenej.api.calls.GetMarketHistory; import cy.agorise.graphenej.api.calls.GetObjects; @@ -34,6 +35,7 @@ import cy.agorise.graphenej.models.AccountProperties; import cy.agorise.graphenej.models.Block; import cy.agorise.graphenej.models.BlockHeader; import cy.agorise.graphenej.models.BucketObject; +import cy.agorise.graphenej.models.FullAccountDetails; import cy.agorise.graphenej.models.HistoryOperationDetail; import cy.agorise.graphenej.models.OperationHistory; import cy.agorise.graphenej.objects.Memo; @@ -156,6 +158,16 @@ public class DeserializationMap { .registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()) .create(); mGsonMap.put(GetAccountHistoryByOperations.class, getAccountHistoryByOperationsGson); + + // GetFullAccounts + mClassMap.put(GetFullAccounts.class, FullAccountDetails.class); + Gson getFullAccountsGson = new GsonBuilder() + .registerTypeAdapter(FullAccountDetails.class, new FullAccountDetails.FullAccountDeserializer()) + .registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer()) + .registerTypeAdapter(Memo.class, new Memo.MemoDeserializer()) + .registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer()) + .create(); + mGsonMap.put(GetFullAccounts.class, getFullAccountsGson); } public Class getReceivedClass(Class _class){ diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/android/NetworkService.java b/graphenej/src/main/java/cy/agorise/graphenej/api/android/NetworkService.java index 6b29e66..f692f15 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/api/android/NetworkService.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/android/NetworkService.java @@ -30,6 +30,7 @@ import cy.agorise.graphenej.api.ConnectionStatusUpdate; import cy.agorise.graphenej.api.bitshares.Nodes; import cy.agorise.graphenej.api.calls.ApiCallable; import cy.agorise.graphenej.api.calls.GetAccounts; +import cy.agorise.graphenej.api.calls.GetFullAccounts; import cy.agorise.graphenej.api.calls.GetLimitOrders; import cy.agorise.graphenej.api.calls.GetMarketHistory; import cy.agorise.graphenej.api.calls.GetObjects; @@ -42,6 +43,7 @@ import cy.agorise.graphenej.models.Block; import cy.agorise.graphenej.models.BlockHeader; import cy.agorise.graphenej.models.BucketObject; import cy.agorise.graphenej.models.DynamicGlobalProperties; +import cy.agorise.graphenej.models.FullAccountDetails; import cy.agorise.graphenej.models.HistoryOperationDetail; import cy.agorise.graphenej.models.JsonRpcNotification; import cy.agorise.graphenej.models.JsonRpcResponse; @@ -390,7 +392,10 @@ public class NetworkService extends Service { }else if(requestClass == GetLimitOrders.class){ Type GetLimitOrdersResponse = new TypeToken>>() {}.getType(); parsedResponse = gson.fromJson(text, GetLimitOrdersResponse); - }else{ + } else if (requestClass == GetFullAccounts.class) { + Type GetFullAccountsResponse = new TypeToken>>(){}.getType(); + parsedResponse = gson.fromJson(text, GetFullAccountsResponse); + } else { Log.w(TAG,"Unknown request class"); } }else{ diff --git a/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetFullAccounts.java b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetFullAccounts.java new file mode 100644 index 0000000..ac7a704 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/api/calls/GetFullAccounts.java @@ -0,0 +1,34 @@ +package cy.agorise.graphenej.api.calls; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import cy.agorise.graphenej.RPC; +import cy.agorise.graphenej.api.ApiAccess; +import cy.agorise.graphenej.models.ApiCall; + +/** + * Wrapper around the 'get_full_accounts' API call. + */ +public class GetFullAccounts implements ApiCallable { + + public static final int REQUIRED_API = ApiAccess.API_NONE; + + private List mUserAccounts; + private boolean mSubscribe; + + public GetFullAccounts(List accounts, boolean subscribe){ + this.mUserAccounts = accounts; + this.mSubscribe = subscribe; + } + + @Override + public ApiCall toApiCall(int apiId, long sequenceId) { + ArrayList params = new ArrayList<>(); + ArrayList accounts = new ArrayList(mUserAccounts); + params.add(accounts); + params.add(mSubscribe); + return new ApiCall(apiId, RPC.CALL_GET_FULL_ACCOUNTS, params, RPC.VERSION, sequenceId); + } +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/models/FullAccountDetails.java b/graphenej/src/main/java/cy/agorise/graphenej/models/FullAccountDetails.java new file mode 100644 index 0000000..55ed6b6 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/models/FullAccountDetails.java @@ -0,0 +1,68 @@ +package cy.agorise.graphenej.models; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +import java.lang.reflect.Type; + +/** + * Model class used in the de-serialization of the response to the 'get_full_accounts' API call. + * @see cy.agorise.graphenej.api.calls.GetFullAccounts + */ +public class FullAccountDetails { + private AccountProperties account; + private Statistics statistics; + + public FullAccountDetails(AccountProperties properties, Statistics statistics){ + this.account = properties; + this.statistics = statistics; + } + + public AccountProperties getAccount() { + return account; + } + + public void setAccount(AccountProperties account) { + this.account = account; + } + + public Statistics getStatistics() { + return statistics; + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public static class Statistics { + public String id; + public String owner; + public String name; + public String most_recent_op; + public long total_ops; + public long removed_ops; + public long total_core_in_orders; + public String core_in_balance; + public boolean has_cashback_vb; + public boolean is_voting; + public long lifetime_fees_paid; + public long pending_fees; + public long pending_vested_fees; + } + + public static class FullAccountDeserializer implements JsonDeserializer { + + @Override + public FullAccountDetails deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonArray array = (JsonArray) json; + JsonObject jsonObject = (JsonObject) array.get(1); + AccountProperties properties = context.deserialize(jsonObject.get("account"), AccountProperties.class); + Statistics statistics = context.deserialize(jsonObject.get("statistics"), Statistics.class); + return new FullAccountDetails(properties, statistics); + } + } +} diff --git a/graphenej/src/test/java/cy/agorise/graphenej/models/FullAccountDetailsTest.java b/graphenej/src/test/java/cy/agorise/graphenej/models/FullAccountDetailsTest.java new file mode 100644 index 0000000..b4ab37f --- /dev/null +++ b/graphenej/src/test/java/cy/agorise/graphenej/models/FullAccountDetailsTest.java @@ -0,0 +1,39 @@ +package cy.agorise.graphenej.models; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import junit.framework.Assert; + +import org.junit.Test; + +import java.lang.reflect.Type; +import java.util.List; + +import cy.agorise.graphenej.AccountOptions; +import cy.agorise.graphenej.Authority; +import cy.agorise.graphenej.objects.Memo; + +public class FullAccountDetailsTest { + + @Test + public void testDeserialization(){ + String serialized = "{\"id\":0,\"jsonrpc\":\"2.0\",\"result\":[[\"bilthon-1\",{\"account\":{\"id\":\"1.2.139205\",\"membership_expiration_date\":\"1970-01-01T00:00:00\",\"registrar\":\"1.2.117600\",\"referrer\":\"1.2.90200\",\"lifetime_referrer\":\"1.2.90200\",\"network_fee_percentage\":2000,\"lifetime_referrer_fee_percentage\":3000,\"referrer_rewards_percentage\":9000,\"name\":\"bilthon-1\",\"owner\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY\",1]],\"address_auths\":[]},\"active\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY\",1]],\"address_auths\":[]},\"options\":{\"memo_key\":\"BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY\",\"voting_account\":\"1.2.5\",\"num_witness\":0,\"num_committee\":0,\"votes\":[],\"extensions\":[]},\"statistics\":\"2.6.139205\",\"whitelisting_accounts\":[],\"blacklisting_accounts\":[],\"whitelisted_accounts\":[],\"blacklisted_accounts\":[],\"owner_special_authority\":[0,{}],\"active_special_authority\":[0,{}],\"top_n_control_flags\":0},\"statistics\":{\"id\":\"2.6.139205\",\"owner\":\"1.2.139205\",\"name\":\"bilthon-1\",\"most_recent_op\":\"2.9.6668024\",\"total_ops\":3,\"removed_ops\":0,\"total_core_in_orders\":0,\"core_in_balance\":71279,\"has_cashback_vb\":false,\"is_voting\":false,\"lifetime_fees_paid\":28721,\"pending_fees\":0,\"pending_vested_fees\":0},\"registrar_name\":\"bitshares-munich-faucet\",\"referrer_name\":\"bitshares-munich\",\"lifetime_referrer_name\":\"bitshares-munich\",\"votes\":[],\"balances\":[{\"id\":\"2.5.44951\",\"owner\":\"1.2.139205\",\"asset_type\":\"1.3.0\",\"balance\":71279,\"maintenance_flag\":false}],\"vesting_balances\":[],\"limit_orders\":[],\"call_orders\":[],\"settle_orders\":[],\"proposals\":[],\"assets\":[],\"withdraws\":[]}],[\"bilthon-2\",{\"account\":{\"id\":\"1.2.139207\",\"membership_expiration_date\":\"1970-01-01T00:00:00\",\"registrar\":\"1.2.117600\",\"referrer\":\"1.2.90200\",\"lifetime_referrer\":\"1.2.90200\",\"network_fee_percentage\":2000,\"lifetime_referrer_fee_percentage\":3000,\"referrer_rewards_percentage\":9000,\"name\":\"bilthon-2\",\"owner\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS7gD2wtSauXpSCBin1rYctBcPWeZieX7YrVk1DuQpg9peczSqTv\",1]],\"address_auths\":[]},\"active\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS7gD2wtSauXpSCBin1rYctBcPWeZieX7YrVk1DuQpg9peczSqTv\",1]],\"address_auths\":[]},\"options\":{\"memo_key\":\"BTS7gD2wtSauXpSCBin1rYctBcPWeZieX7YrVk1DuQpg9peczSqTv\",\"voting_account\":\"1.2.5\",\"num_witness\":0,\"num_committee\":0,\"votes\":[],\"extensions\":[]},\"statistics\":\"2.6.139207\",\"whitelisting_accounts\":[],\"blacklisting_accounts\":[],\"whitelisted_accounts\":[],\"blacklisted_accounts\":[],\"owner_special_authority\":[0,{}],\"active_special_authority\":[0,{}],\"top_n_control_flags\":0},\"statistics\":{\"id\":\"2.6.139207\",\"owner\":\"1.2.139207\",\"name\":\"bilthon-2\",\"most_recent_op\":\"2.9.6159244\",\"total_ops\":1,\"removed_ops\":0,\"total_core_in_orders\":0,\"core_in_balance\":0,\"has_cashback_vb\":false,\"is_voting\":false,\"lifetime_fees_paid\":0,\"pending_fees\":0,\"pending_vested_fees\":0},\"registrar_name\":\"bitshares-munich-faucet\",\"referrer_name\":\"bitshares-munich\",\"lifetime_referrer_name\":\"bitshares-munich\",\"votes\":[],\"balances\":[],\"vesting_balances\":[],\"limit_orders\":[],\"call_orders\":[],\"settle_orders\":[],\"proposals\":[],\"assets\":[],\"withdraws\":[]}]]}"; + Gson gson = new GsonBuilder() + .registerTypeAdapter(FullAccountDetails.class, new FullAccountDetails.FullAccountDeserializer()) + .registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer()) + .registerTypeAdapter(Memo.class, new Memo.MemoDeserializer()) + .registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer()) + .create(); + Type FullAccountDetailsResponse = new TypeToken>>() {}.getType(); + JsonRpcResponse> response = gson.fromJson(serialized, FullAccountDetailsResponse); + Assert.assertNotNull(response.result); + Assert.assertNull(response.error); + List fullAccountDetailsList = response.result; + Assert.assertNotNull(fullAccountDetailsList); + Assert.assertEquals(2, fullAccountDetailsList.size()); + Assert.assertNotNull(fullAccountDetailsList.get(0).getAccount()); + Assert.assertEquals("bilthon-1", fullAccountDetailsList.get(0).getAccount().name); + } +} diff --git a/sample/src/main/java/cy/agorise/labs/sample/CallsActivity.java b/sample/src/main/java/cy/agorise/labs/sample/CallsActivity.java index 19b677e..4db3d3e 100644 --- a/sample/src/main/java/cy/agorise/labs/sample/CallsActivity.java +++ b/sample/src/main/java/cy/agorise/labs/sample/CallsActivity.java @@ -48,6 +48,7 @@ public class CallsActivity extends AppCompatActivity { RPC.CALL_GET_ACCOUNT_BY_NAME, RPC.CALL_GET_LIMIT_ORDERS, RPC.CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS, + RPC.CALL_GET_FULL_ACCOUNTS, RPC.CALL_SET_SUBSCRIBE_CALLBACK }; diff --git a/sample/src/main/java/cy/agorise/labs/sample/PerformCallActivity.java b/sample/src/main/java/cy/agorise/labs/sample/PerformCallActivity.java index 289dcfc..4dc2eac 100644 --- a/sample/src/main/java/cy/agorise/labs/sample/PerformCallActivity.java +++ b/sample/src/main/java/cy/agorise/labs/sample/PerformCallActivity.java @@ -17,6 +17,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import butterknife.BindView; @@ -32,6 +33,7 @@ import cy.agorise.graphenej.api.calls.GetAccountByName; import cy.agorise.graphenej.api.calls.GetAccountHistoryByOperations; import cy.agorise.graphenej.api.calls.GetAccounts; import cy.agorise.graphenej.api.calls.GetBlock; +import cy.agorise.graphenej.api.calls.GetFullAccounts; import cy.agorise.graphenej.api.calls.GetLimitOrders; import cy.agorise.graphenej.api.calls.GetObjects; import cy.agorise.graphenej.api.calls.ListAssets; @@ -130,6 +132,9 @@ public class PerformCallActivity extends ConnectedActivity { break; case RPC.CALL_GET_LIMIT_ORDERS: setupGetLimitOrders(); + case RPC.CALL_GET_FULL_ACCOUNTS: + setupGetFullAccounts(); + break; default: Log.d(TAG,"Default called"); } @@ -239,6 +244,12 @@ public class PerformCallActivity extends ConnectedActivity { param3.setInputType(InputType.TYPE_CLASS_NUMBER); } + private void setupGetFullAccounts(){ + requiredInput(1); + mParam1View.setHint(getString(R.string.get_full_accounts_arg1)); + param1.setInputType(InputType.TYPE_CLASS_TEXT); + } + private void requiredInput(int inputCount){ if(inputCount == 1){ mParam1View.setVisibility(View.VISIBLE); @@ -296,6 +307,8 @@ public class PerformCallActivity extends ConnectedActivity { case RPC.CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS: getAccountHistoryByOperations(); break; + case RPC.CALL_GET_FULL_ACCOUNTS: + getFullAccounts(); default: Log.d(TAG,"Default called"); } @@ -370,6 +383,12 @@ public class PerformCallActivity extends ConnectedActivity { } } + private void getFullAccounts(){ + ArrayList accounts = new ArrayList<>(); + accounts.addAll(Arrays.asList(param1.getText().toString().split(","))); + long id = mNetworkService.sendMessage(new GetFullAccounts(accounts, false), GetFullAccounts.REQUIRED_API); + } + /** * Internal method that will decide what to do with each JSON-RPC response * diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 1776b5c..948c99c 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -51,4 +51,7 @@ Asset A Asset B Number of orders + + + Account names or ids, separated by commas