package cy.agorise.labs.sample; import android.content.ComponentName; import android.content.res.Resources; import android.os.Bundle; import android.os.IBinder; import android.support.design.widget.TextInputEditText; import android.support.design.widget.TextInputLayout; import android.text.InputType; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.google.common.primitives.UnsignedLong; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.bitcoinj.core.ECKey; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import cy.agorise.graphenej.Asset; import cy.agorise.graphenej.AssetAmount; import cy.agorise.graphenej.BaseOperation; import cy.agorise.graphenej.BlockData; import cy.agorise.graphenej.BrainKey; import cy.agorise.graphenej.Memo; import cy.agorise.graphenej.OperationType; import cy.agorise.graphenej.RPC; import cy.agorise.graphenej.Transaction; import cy.agorise.graphenej.UserAccount; import cy.agorise.graphenej.Util; import cy.agorise.graphenej.api.ConnectionStatusUpdate; import cy.agorise.graphenej.api.android.DeserializationMap; import cy.agorise.graphenej.api.android.RxBus; import cy.agorise.graphenej.api.calls.BroadcastTransaction; import cy.agorise.graphenej.api.calls.GetAccountBalances; 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.GetAssets; import cy.agorise.graphenej.api.calls.GetBlock; import cy.agorise.graphenej.api.calls.GetDynamicGlobalProperties; import cy.agorise.graphenej.api.calls.GetFullAccounts; import cy.agorise.graphenej.api.calls.GetKeyReferences; import cy.agorise.graphenej.api.calls.GetLimitOrders; import cy.agorise.graphenej.api.calls.GetObjects; import cy.agorise.graphenej.api.calls.GetRequiredFees; import cy.agorise.graphenej.api.calls.GetTransaction; import cy.agorise.graphenej.api.calls.ListAssets; import cy.agorise.graphenej.errors.MalformedAddressException; import cy.agorise.graphenej.models.JsonRpcResponse; import cy.agorise.graphenej.operations.TransferOperation; import cy.agorise.graphenej.operations.TransferOperationBuilder; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; public class PerformCallActivity extends ConnectedActivity { private final String TAG = this.getClass().getName(); @BindView(R.id.response) TextView mResponseView; @BindView(R.id.container_param1) TextInputLayout mParam1View; @BindView(R.id.container_param2) TextInputLayout mParam2View; @BindView(R.id.container_param3) TextInputLayout mParam3View; @BindView(R.id.container_param4) TextInputLayout mParam4View; @BindView(R.id.param1) TextInputEditText param1; @BindView(R.id.param2) TextInputEditText param2; @BindView(R.id.param3) TextInputEditText param3; @BindView(R.id.param4) TextInputEditText param4; @BindView(R.id.button_send) Button mButtonSend; // Field used to map a request id to its type private HashMap responseMap = new HashMap<>(); // Current request type. Ex: 'get_objects', 'get_accounts', etc private String mRPC; private Disposable mDisposable; private Gson gson = new GsonBuilder() .setExclusionStrategies(new DeserializationMap.SkipAccountOptionsStrategy(), new DeserializationMap.SkipAssetOptionsStrategy()) .registerTypeAdapter(Memo.class, new Memo.MemoSerializer()) .create(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_perform_call); ButterKnife.bind(this); mRPC = getIntent().getStringExtra(Constants.KEY_SELECTED_CALL); Log.d(TAG,"Selected call: "+mRPC); switch (mRPC){ case RPC.CALL_GET_OBJECTS: setupGetObjects(); break; case RPC.CALL_GET_ACCOUNTS: setupGetAccounts(); break; case RPC.CALL_GET_BLOCK: setupGetBlock(); break; case RPC.CALL_GET_BLOCK_HEADER: setupGetBlockHeader(); break; case RPC.CALL_GET_MARKET_HISTORY: setupGetMarketHistory(); break; case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY: setupGetRelativeAccountHistory(); break; case RPC.CALL_GET_REQUIRED_FEES: setupGetRequiredFees(); break; case RPC.CALL_LOOKUP_ASSET_SYMBOLS: setupLookupAssetSymbols(); break; case RPC.CALL_LIST_ASSETS: setupListAssets(); break; case RPC.CALL_GET_ASSETS: setupGetAssets(); break; case RPC.CALL_GET_ACCOUNT_BY_NAME: setupAccountByName(); break; case RPC.CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS: setupGetAccountHistoryByOperations(); break; case RPC.CALL_GET_LIMIT_ORDERS: setupGetLimitOrders(); break; case RPC.CALL_GET_FULL_ACCOUNTS: setupGetFullAccounts(); break; case RPC.CALL_GET_DYNAMIC_GLOBAL_PROPERTIES: setupGetDynamicGlobalProperties(); break; case RPC.CALL_GET_KEY_REFERENCES: setupGetKeyReferences(); break; case RPC.CALL_GET_ACCOUNT_BALANCES: setupGetAccountBalances(); break; case RPC.CALL_BROADCAST_TRANSACTION: setupBroadcastTransaction(); break; case RPC.CALL_GET_TRANSACTION: setupGetTransaction(); default: Log.d(TAG,"Default called"); } mDisposable = RxBus.getBusInstance() .asFlowable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer() { @Override public void accept(Object message) throws Exception { Log.d(TAG,"accept. Msg class: "+message.getClass()); if(message instanceof ConnectionStatusUpdate){ // TODO: Update UI ? }else if(message instanceof JsonRpcResponse){ handleJsonRpcResponse((JsonRpcResponse) message); } } }); } private void setupGetObjects(){ requiredInput(1); mParam1View.setHint(getResources().getString(R.string.get_objects_arg1)); } private void setupGetAccounts(){ requiredInput(1); mParam1View.setHint(getResources().getString(R.string.get_accounts_arg1)); } private void setupGetBlock(){ requiredInput(1); mParam1View.setHint(getResources().getString(R.string.get_block_arg1)); } private void setupGetBlockHeader(){ requiredInput(1); mParam1View.setHint(getResources().getString(R.string.get_block_arg1)); } private void setupGetMarketHistory(){ requiredInput(4); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.get_market_history_arg1)); mParam2View.setHint(resources.getString(R.string.get_market_history_arg2)); mParam3View.setHint(resources.getString(R.string.get_market_history_arg3)); mParam4View.setHint(resources.getString(R.string.get_market_history_arg4)); } private void setupGetRelativeAccountHistory(){ requiredInput(4); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.get_relative_account_history_arg1)); mParam2View.setHint(resources.getString(R.string.get_relative_account_history_arg2)); mParam3View.setHint(resources.getString(R.string.get_relative_account_history_arg3)); mParam4View.setHint(resources.getString(R.string.get_relative_account_history_arg4)); } private void setupGetRequiredFees(){ requiredInput(1); mParam1View.setHint(getString(R.string.get_required_fees_asset)); } private void setupLookupAssetSymbols(){ requiredInput(4); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.lookup_asset_symbols_arg1)); mParam2View.setHint(resources.getString(R.string.lookup_asset_symbols_arg2)); mParam3View.setHint(resources.getString(R.string.lookup_asset_symbols_arg3)); mParam4View.setHint(resources.getString(R.string.lookup_asset_symbols_arg4)); } private void setupListAssets(){ requiredInput(2); mParam1View.setHint(getString(R.string.list_assets_arg1)); mParam2View.setHint(getString(R.string.list_assets_arg2)); param2.setInputType(InputType.TYPE_CLASS_NUMBER); } private void setupGetAssets(){ requiredInput(1); mParam1View.setHint(getString(R.string.get_assets_arg)); } private void setupAccountByName(){ requiredInput(1); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.get_accounts_by_name_arg1)); param1.setInputType(InputType.TYPE_CLASS_TEXT); } private void setupGetAccountHistoryByOperations(){ requiredInput(4); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.get_account_history_by_operations_arg1)); mParam2View.setHint(resources.getString(R.string.get_account_history_by_operations_arg2)); mParam3View.setHint(resources.getString(R.string.get_account_history_by_operations_arg3)); mParam4View.setHint(resources.getString(R.string.get_account_history_by_operations_arg4)); param2.setText("0"); // Only transfer de-serialization is currently supported by the library! param2.setEnabled(false); param2.setInputType(InputType.TYPE_CLASS_NUMBER); param3.setInputType(InputType.TYPE_CLASS_NUMBER); param4.setInputType(InputType.TYPE_CLASS_NUMBER); } private void setupGetLimitOrders(){ requiredInput(3); Resources resources = getResources(); mParam1View.setHint(resources.getString(R.string.get_limit_orders_arg1)); mParam2View.setHint(resources.getString(R.string.get_limit_orders_arg2)); mParam3View.setHint(resources.getString(R.string.get_limit_orders_arg3)); param1.setInputType(InputType.TYPE_CLASS_TEXT); param2.setInputType(InputType.TYPE_CLASS_TEXT); 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 setupGetDynamicGlobalProperties(){ requiredInput(0); } private void setupGetKeyReferences(){ requiredInput(1); // Test address param1.setText("BTS8a7XJ94u1traaLGFHw6NgpvUaxmbG4MyCcZC1hBj9HCBuMEwXP"); } private void setupGetAccountBalances(){ requiredInput(2); param1.setHint(R.string.get_account_balances_arg1); param2.setHint(R.string.get_account_balances_arg2); } private void setupBroadcastTransaction(){ requiredInput(2); param1.setText("1.2.116354"); param2.setText("1"); } private void setupGetTransaction(){ requiredInput(2); param1.setText("13282815"); param2.setText("0"); } private void requiredInput(int inputCount){ if(inputCount == 0){ mParam1View.setVisibility(View.GONE); mParam2View.setVisibility(View.GONE); mParam3View.setVisibility(View.GONE); mParam4View.setVisibility(View.GONE); }else if(inputCount == 1){ mParam1View.setVisibility(View.VISIBLE); mParam2View.setVisibility(View.GONE); mParam3View.setVisibility(View.GONE); mParam4View.setVisibility(View.GONE); }else if(inputCount == 2){ mParam1View.setVisibility(View.VISIBLE); mParam2View.setVisibility(View.VISIBLE); mParam3View.setVisibility(View.GONE); mParam4View.setVisibility(View.GONE); }else if(inputCount == 3){ mParam1View.setVisibility(View.VISIBLE); mParam2View.setVisibility(View.VISIBLE); mParam3View.setVisibility(View.VISIBLE); mParam4View.setVisibility(View.GONE); }else if(inputCount == 4){ mParam1View.setVisibility(View.VISIBLE); mParam2View.setVisibility(View.VISIBLE); mParam3View.setVisibility(View.VISIBLE); mParam4View.setVisibility(View.VISIBLE); } } @OnClick(R.id.button_send) public void onSendClicked(Button v){ switch (mRPC){ case RPC.CALL_GET_OBJECTS: sendGetObjectsRequest(); break; case RPC.CALL_GET_ACCOUNTS: sendGetAccountsRequest(); break; case RPC.CALL_GET_BLOCK: break; case RPC.CALL_GET_BLOCK_HEADER: break; case RPC.CALL_GET_MARKET_HISTORY: break; case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY: break; case RPC.CALL_GET_REQUIRED_FEES: sendGetRequiredFees(); break; case RPC.CALL_LOOKUP_ASSET_SYMBOLS: break; case RPC.CALL_LIST_ASSETS: sendListAssets(); break; case RPC.CALL_GET_ASSETS: sendGetAssets(); break; case RPC.CALL_GET_ACCOUNT_BY_NAME: getAccountByName(); break; case RPC.CALL_GET_LIMIT_ORDERS: getLimitOrders(); break; case RPC.CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS: getAccountHistoryByOperations(); break; case RPC.CALL_GET_FULL_ACCOUNTS: getFullAccounts(); break; case RPC.CALL_GET_DYNAMIC_GLOBAL_PROPERTIES: getDynamicGlobalProperties(); break; case RPC.CALL_GET_KEY_REFERENCES: getKeyReferences(); break; case RPC.CALL_GET_ACCOUNT_BALANCES: getAccountBalances(); break; case RPC.CALL_BROADCAST_TRANSACTION: broadcastTransaction(); break; case RPC.CALL_GET_TRANSACTION: getTransaction(); default: Log.d(TAG,"Default called"); } } private void sendGetObjectsRequest(){ String objectId = param1.getText().toString(); if(objectId.matches("\\d\\.\\d{1,3}\\.\\d{1,10}")){ ArrayList array = new ArrayList<>(); array.add(objectId); GetObjects getObjects = new GetObjects(array); long id = mNetworkService.sendMessage(getObjects, GetObjects.REQUIRED_API); responseMap.put(id, mRPC); }else{ param1.setError(getResources().getString(R.string.error_input_id)); } } private void sendGetAccountsRequest(){ String userId = param1.getText().toString(); if(userId.matches("\\d\\.\\d{1,3}\\.\\d{1,10}")){ GetAccounts getAccounts = new GetAccounts(new UserAccount(userId)); long id = mNetworkService.sendMessage(getAccounts, GetBlock.REQUIRED_API); responseMap.put(id, mRPC); }else{ param1.setError(getResources().getString(R.string.error_input_id)); } } private void sendGetRequiredFees(){ String input = param1.getText().toString(); ArrayList operations = new ArrayList<>(); AssetAmount transfer = new AssetAmount(UnsignedLong.valueOf("1000"), new Asset("1.3.0")); AssetAmount fee = new AssetAmount(UnsignedLong.valueOf("1000"), new Asset("1.3.0")); operations.add(new TransferOperation(new UserAccount("1.2.12300"), new UserAccount("1.2.12301"), fee, transfer)); long id = mNetworkService.sendMessage(new GetRequiredFees(operations, new Asset(input)), GetRequiredFees.REQUIRED_API); responseMap.put(id, mRPC); } private void sendListAssets(){ try{ String lowerBound = param1.getText().toString(); int limit = Integer.parseInt(param2.getText().toString()); ListAssets listAssets = new ListAssets(lowerBound, limit); long id = mNetworkService.sendMessage(listAssets, ListAssets.REQUIRED_API); responseMap.put(id, mRPC); }catch(NumberFormatException e){ Toast.makeText(this, getString(R.string.error_number_format), Toast.LENGTH_SHORT).show(); Log.e(TAG,"NumberFormatException while reading limit value. Msg: "+e.getMessage()); } } private void sendGetAssets(){ String assetIds = param1.getText().toString(); ArrayList assetList = new ArrayList<>(); for(String id :assetIds.split(",")){ assetList.add(new Asset(id)); } long id = mNetworkService.sendMessage(new GetAssets(assetList), GetAssets.REQUIRED_API); responseMap.put(id, mRPC); } private void getAccountByName(){ String accountName = param1.getText().toString(); long id = mNetworkService.sendMessage(new GetAccountByName(accountName), GetAccountByName.REQUIRED_API); responseMap.put(id, mRPC); } private void getLimitOrders(){ String assetA = param1.getText().toString(); String assetB = param2.getText().toString(); try{ int limit = Integer.parseInt(param3.getText().toString()); long id = mNetworkService.sendMessage(new GetLimitOrders(assetA, assetB, limit), GetLimitOrders.REQUIRED_API); }catch(NumberFormatException e){ Toast.makeText(this, getString(R.string.error_number_format), Toast.LENGTH_SHORT).show(); Log.e(TAG,"NumberFormatException while trying to read limit value. Msg: "+e.getMessage()); } } private void getAccountHistoryByOperations(){ try{ String account = param1.getText().toString(); ArrayList operationTypes = new ArrayList<>(); operationTypes.add(OperationType.TRANSFER_OPERATION); // Currently restricted to transfer operations long start = Long.parseLong(param3.getText().toString()); long limit = Long.parseLong(param4.getText().toString()); long id = mNetworkService.sendMessage(new GetAccountHistoryByOperations(account, operationTypes, start, limit), GetAccountHistoryByOperations.REQUIRED_API); responseMap.put(id, mRPC); }catch(NumberFormatException e){ Toast.makeText(this, getString(R.string.error_number_format), Toast.LENGTH_SHORT).show(); Log.e(TAG,"NumberFormatException while trying to read arguments for 'get_account_history_by_operations'. Msg: "+e.getMessage()); } } 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); responseMap.put(id, mRPC); } private void getDynamicGlobalProperties(){ long id = mNetworkService.sendMessage(new GetDynamicGlobalProperties(), GetDynamicGlobalProperties.REQUIRED_API); responseMap.put(id, mRPC); } private void getKeyReferences(){ String address = param1.getText().toString(); long id = 0; try { id = mNetworkService.sendMessage(new GetKeyReferences(address), GetKeyReferences.REQUIRED_API); responseMap.put(id, mRPC); } catch (MalformedAddressException | IllegalArgumentException e) { Log.e(TAG,"MalformedAddressException. Msg: "+e.getMessage()); Toast.makeText(this, "Malformed address exception", Toast.LENGTH_SHORT).show(); param1.setText(""); } } private void getAccountBalances(){ String accountId = param1.getText().toString(); UserAccount userAccount = new UserAccount(accountId); String assets = param2.getText().toString(); String[] assetArray = assets.split(","); List assetList = new ArrayList(); for(String id : assetArray) assetList.add(new Asset(id)); long id = mNetworkService.sendMessage(new GetAccountBalances(userAccount, assetList), GetAccountBalances.REQUIRED_API); responseMap.put(id, mRPC); } private void getTransaction(){ long blockNum = Long.parseLong(param1.getText().toString()); long index = Long.parseLong(param2.getText().toString()); long id = mNetworkService.sendMessage(new GetTransaction(blockNum, index), GetTransaction.REQUIRED_API); responseMap.put(id, mRPC); } private void broadcastTransaction(){ String destinationId = param1.getText().toString(); String amount = param2.getText().toString(); UnsignedLong transferAmount = UnsignedLong.valueOf(amount).times(UnsignedLong.valueOf(100000)); TransferOperation operation = new TransferOperationBuilder() .setSource(new UserAccount("1.2.1029856")) .setDestination(new UserAccount(destinationId)) .setTransferAmount(new AssetAmount( transferAmount, new Asset("1.3.0"))) .setFee(new AssetAmount(UnsignedLong.valueOf("10420"), new Asset("1.3.0"))) .build(); ArrayList ops = new ArrayList<>(); ops.add(operation); // >> Replace with your brainkey << BrainKey brainKey = new BrainKey(">> Place your brainkey here <<", 0); ECKey privKey = brainKey.getPrivateKey(); // Use valid BlockData BlockData blockData = new BlockData(44542, 3342959171L, 1544917202L); Transaction tx = new Transaction(privKey, blockData, ops); long id = mNetworkService.sendMessage(new BroadcastTransaction(tx), BroadcastTransaction.REQUIRED_API); responseMap.put(id, mRPC); } /** * Internal method that will decide what to do with each JSON-RPC response * * @param response The JSON-RPC api call response */ private void handleJsonRpcResponse(JsonRpcResponse response){ long id = response.id; if(responseMap.get(id) != null){ String request = responseMap.get(id); switch(request){ case RPC.CALL_GET_ACCOUNT_BALANCES: List balances = (List) response.result; StringBuilder builder = new StringBuilder(); for(AssetAmount assetAmount : balances) builder.append(assetAmount).append("\n"); mResponseView.setText(builder.toString()); break; case RPC.CALL_GET_TRANSACTION: Transaction tx = (Transaction) response.result; mResponseView.setText(mResponseView.getText() + String.format("[%s][%s]", tx.toString(), Util.bytesToHex(tx.getHash()))); break; case RPC.CALL_GET_ACCOUNTS: case RPC.CALL_GET_BLOCK: case RPC.CALL_GET_BLOCK_HEADER: case RPC.CALL_GET_MARKET_HISTORY: case RPC.CALL_GET_ACCOUNT_HISTORY: case RPC.CALL_GET_RELATIVE_ACCOUNT_HISTORY: case RPC.CALL_GET_REQUIRED_FEES: case RPC.CALL_LOOKUP_ASSET_SYMBOLS: case RPC.CALL_LIST_ASSETS: case RPC.CALL_GET_ASSETS: case RPC.CALL_GET_ACCOUNT_BY_NAME: case RPC.CALL_GET_LIMIT_ORDERS: case RPC.CALL_GET_ACCOUNT_HISTORY_BY_OPERATIONS: case RPC.CALL_GET_FULL_ACCOUNTS: case RPC.CALL_GET_DYNAMIC_GLOBAL_PROPERTIES: case RPC.CALL_GET_KEY_REFERENCES: mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n"); break; default: Log.w(TAG,"Case not handled"); if(response.result != null) mResponseView.setText(mResponseView.getText() + response.result.toString()); else if(response.error != null) mResponseView.setText(mResponseView.getText() + String.format("Error code: %d, Msg: %s", response.error.code, response.error.message)); else mResponseView.setText(mResponseView.getText() + "\nnull"); } // Remember to remove the used id entry from the map, as it would // otherwise just increase the app's memory usage responseMap.remove(id); }else{ Log.d(TAG,"No entry"); mResponseView.setText(mResponseView.getText() + gson.toJson(response, JsonRpcResponse.class) + "\n"); } } @Override protected void onDestroy() { super.onDestroy(); if(!mDisposable.isDisposed()) mDisposable.dispose(); } @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { // Called upon NetworkService connection } @Override public void onServiceDisconnected(ComponentName componentName) { // Called upon NetworkService disconnection } }