com.bringcommunications.etherpay.SendActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.bringcommunications.etherpay.SendActivity.java

Source

/*
    
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
    
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
    
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
    
*/

package com.bringcommunications.etherpay;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.support.v4.app.NavUtils;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import org.ethereum.core.Transaction;

/*
import org.ethereum.core.Block;
import org.ethereum.core.TransactionReceipt;
import org.ethereum.facade.Ethereum;
import org.ethereum.facade.EthereumFactory;
import org.ethereum.listener.EthereumListenerAdapter;
*/

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import static org.ethereum.crypto.HashUtil.sha3;
import static org.ethereum.util.ByteUtil.longToBytesNoLeadZeroes;

public class SendActivity extends AppCompatActivity
        implements Payment_Processor_Client, AdapterView.OnItemSelectedListener {
    //HTTP_Query_Client

    private FrameLayout overlay_frame_layout;
    private SendActivity context;
    private static final float WEI_PER_ETH = (float) 1000000000000000000.0;
    private SharedPreferences preferences;
    private Hex hex;
    //inputs
    private String acct_addr = "";
    private String private_key = "";
    private String to_addr = "";
    private String auto_pay = "";
    private boolean show_gas = false;
    private boolean show_data = false;
    private boolean send_is_done = false;
    private float eth_size;
    private float eth_balance;
    private float price;
    //we set these
    private long gas_limit = Util.DEFAULT_GAS_LIMIT;
    private String data = "";
    private long nonce;
    private String txid = "";

    private enum Denomination {
        ETH, FINNEY
    };

    private Denomination denomination = Denomination.ETH;
    private Toast toast = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        overlay_frame_layout = new FrameLayout(getApplicationContext());
        setContentView(overlay_frame_layout);
        //
        context = this;
        hex = new Hex();
        preferences = getSharedPreferences("etherpay.bringcommunications.com", MODE_PRIVATE);
        private_key = preferences.getString("key", private_key);
        acct_addr = preferences.getString("acct_addr", acct_addr);
        long wei_balance = preferences.getLong("balance", 0);
        eth_balance = (float) wei_balance / Util.WEI_PER_ETH;
        price = preferences.getFloat("price", price);
        show_gas = preferences.getBoolean("show_gas", show_gas);
        show_data = preferences.getBoolean("show_data", show_data);
        boolean denomination_eth = preferences.getBoolean("denomination_eth", true);
        System.out.println("denomination_eth is " + denomination_eth);
        denomination = denomination_eth ? Denomination.ETH : Denomination.FINNEY;
        auto_pay = getIntent().getStringExtra("AUTO_PAY");
        to_addr = getIntent().getStringExtra("TO_ADDR");
        String size_str = getIntent().getStringExtra("SIZE");
        eth_size = Float.valueOf(size_str);
        data = getIntent().getStringExtra("DATA");
        send_is_done = false;
        //
        View activity_send_view = getLayoutInflater().inflate(R.layout.activity_send, overlay_frame_layout, false);
        setContentView(activity_send_view);
        //
        Spinner dropdown = (Spinner) findViewById(R.id.denomination);
        String[] items = new String[] { "ETH", "Finney" };
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item,
                items);
        dropdown.setSelection((denomination == Denomination.ETH) ? 0 : 1);
        dropdown.setOnItemSelectedListener(this);
        dropdown.setAdapter(adapter);
        //
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        String app_name = getResources().getString(R.string.app_name);
        toolbar.setTitle(app_name);
        toolbar.setSubtitle("Send Payment");
        toolbar.setBackgroundResource(R.color.color_toolbar);
        setSupportActionBar(toolbar);
        //
        TextView to_addr_view = (TextView) findViewById(R.id.to_addr);
        to_addr_view.setText(to_addr);
        //
        TextView size_view = (TextView) findViewById(R.id.size);
        size_str = (denomination == Denomination.ETH) ? String.format("%1.03f", eth_size)
                : String.format("%03d", (int) (eth_size * 1000 + 0.5));
        size_view.setText(size_str);
        //
        LinearLayout gas_layout = (LinearLayout) findViewById(R.id.gas_layout);
        TextView gas_prompt_view = (TextView) findViewById(R.id.gas_prompt);
        TextView gas_view = (TextView) findViewById(R.id.gas);
        ImageButton gas_help_view = (ImageButton) findViewById(R.id.gas_help);
        if (show_gas) {
            String gas_str = String.format("%7d", gas_limit);
            gas_view.setText(gas_str);
            gas_layout.setVisibility(View.VISIBLE);
            gas_prompt_view.setVisibility(View.VISIBLE);
            gas_help_view.setVisibility(View.VISIBLE);
            gas_view.setVisibility(View.VISIBLE);
        } else {
            gas_layout.setVisibility(View.GONE);
            gas_prompt_view.setVisibility(View.GONE);
            gas_help_view.setVisibility(View.GONE);
            gas_view.setVisibility(View.GONE);
        }

        LinearLayout data_layout = (LinearLayout) findViewById(R.id.data_layout);
        TextView data_prompt_view = (TextView) findViewById(R.id.data_prompt);
        TextView data_view = (TextView) findViewById(R.id.data);
        ImageButton data_help_view = (ImageButton) findViewById(R.id.data_help);
        if (show_data) {
            data_view.setText(data);
            data_layout.setVisibility(View.VISIBLE);
            data_prompt_view.setVisibility(View.VISIBLE);
            data_help_view.setVisibility(View.VISIBLE);
            data_view.setVisibility(View.VISIBLE);
        } else {
            data = "";
            data_layout.setVisibility(View.GONE);
            data_prompt_view.setVisibility(View.GONE);
            data_help_view.setVisibility(View.GONE);
            data_view.setVisibility(View.GONE);
        }

        //
        //sanity check
        if (to_addr.length() != 42) {
            this.finish();
        }
    }

    //returns false => no options menu
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.send_options, menu);
        menu.findItem(R.id.show_gas).setChecked(show_gas);
        menu.findItem(R.id.show_data).setChecked(show_data);
        return (true);
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.show_gas: {
            boolean show_gas = item.isChecked() ? false : true;
            item.setChecked(show_gas);
            SharedPreferences.Editor preferences_editor = preferences.edit();
            preferences_editor.putBoolean("show_gas", show_gas);
            preferences_editor.apply();
            recreate();
            return true;
        }
        case R.id.show_data: {
            boolean show_data = item.isChecked() ? false : true;
            item.setChecked(show_data);
            SharedPreferences.Editor preferences_editor = preferences.edit();
            preferences_editor.putBoolean("show_data", show_data);
            preferences_editor.apply();
            recreate();
            return true;
        }
        case R.id.help:
            do_help(R.string.send_help_title, R.string.send_help);
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    //this onItemSelected is called when a new denomination is selected from the denomination drop-down
    @Override
    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
        EditText size_view = (EditText) findViewById(R.id.size);
        String cur_size_str = size_view.getText().toString();
        float cur_size = Float.valueOf(cur_size_str);
        eth_size = (denomination == Denomination.ETH) ? cur_size : cur_size / 1000;
        denomination = (position == 0) ? Denomination.ETH : Denomination.FINNEY;
        if (denomination == Denomination.FINNEY) {
            eth_size = (float) ((int) (eth_size * 1000 + 0.5)) / 1000;
        }
        boolean denomination_eth = (denomination == Denomination.ETH) ? true : false;
        SharedPreferences.Editor preferences_editor = preferences.edit();
        preferences_editor.putBoolean("denomination_eth", denomination_eth);
        System.out.println("set denomination_eth to " + denomination_eth + ", id = " + id);
        preferences_editor.apply();
        String size_str = (denomination == Denomination.ETH) ? String.format("%1.03f", eth_size)
                : String.format("%03d", (int) (eth_size * 1000 + 0.5));
        size_view.setText(size_str);
    }

    public void onNothingSelected(AdapterView<?> parent) {
    }

    public void onResume() {
        super.onResume(); // Always call the superclass method first
        if (auto_pay.equals("true")) {
            Button pay_button = (Button) findViewById(R.id.pay_button);
            pay_button.setEnabled(false);
            TextView size_view = (TextView) findViewById(R.id.size);
            size_view.setKeyListener(null);
            size_view.setCursorVisible(false);
            size_view.setFocusable(false);
            EditText data_view = (EditText) findViewById(R.id.data);
            data_view.setKeyListener(null);
            data_view.setCursorVisible(false);
            data_view.setFocusable(false);
            do_pay(null);
        }
    }

    //displays the txid -- but also displays a message informing the user that the transaction was completed.
    //waits for the user to acknowledge the message -- AND THEN RETURNS TO THE PARENT ACTIVITY!
    private void dsp_txid_and_exit() {
        /*
        TextView txid_view = (TextView) findViewById(R.id.txid);
        txid_view.setText(txid);
        if (auto_pay.equals("true")) {
          String msg = txid.isEmpty() ? "transaction failed" : "your transaction was sent successfully";
          Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
          NavUtils.navigateUpFromSameTask(context);
          this.finish();
        } else
        */
        {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            String title = txid.isEmpty() ? "Error" : "Transaction Sent";
            String msg = txid.isEmpty()
                    ? "An error occurred while attempting this transaction -- press OK to continue"
                    : "your transaction was sent successfully -- press OK to continue";
            builder.setTitle(title);
            builder.setMessage(msg);
            builder.setCancelable(true);
            builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                    NavUtils.navigateUpFromSameTask(context);
                    context.finish();
                }
            });
            AlertDialog alert = builder.create();
            alert.show();
        }
    }

    public void do_size_help(View view) {
        do_help(R.string.size_help_title, R.string.size_help);
    }

    public void do_gas_help(View view) {
        do_help(R.string.gas_help_title, R.string.gas_help);
    }

    public void do_data_help(View view) {
        do_help(R.string.data_help_title, R.string.data_help);
    }

    public void do_pay(View view) {
        if (send_is_done)
            return;
        //validate size... we check for sufficient balance later...
        EditText size_view = (EditText) findViewById(R.id.size);
        String user_size_str = size_view.getText().toString();
        float user_size = Float.valueOf(user_size_str);
        eth_size = (denomination == Denomination.ETH) ? user_size : user_size / 1000;
        if (eth_size == 0) {
            Toast.makeText(context, "Cannot send zero ETH", Toast.LENGTH_LONG).show();
            return;
        }
        if (show_gas) {
            TextView gas_view = (TextView) findViewById(R.id.gas);
            String gas_limit_str = gas_view.getText().toString().trim();
            try {
                gas_limit = Long.valueOf(gas_limit_str);
            } catch (NumberFormatException e) {
                Toast.makeText(context, "Unable to parse Gas limit: " + gas_limit_str, Toast.LENGTH_LONG).show();
                return;
            }
        }
        if (gas_limit < Util.DEFAULT_GAS_LIMIT) {
            Toast.makeText(context, "Gas limit is too low -- transaction might not succeed!", Toast.LENGTH_LONG)
                    .show();
            return;
        }
        //ensure sufficient funds
        long gas_price = preferences.getLong("gas_price", Util.DEFAULT_GAS_PRICE);
        float max_gas_eth = (gas_limit * gas_price) / WEI_PER_ETH;
        if (eth_size + max_gas_eth > eth_balance) {
            String balance_str = String.format("%1.06f", eth_balance);
            String size_str = String.format("%1.06f", eth_size);
            String gas_str = String.format("%1.08f", max_gas_eth);
            String msg = "Balance (" + balance_str + ") is not sufficient to cover " + size_str + " ETH, plus "
                    + gas_str + " GAS";
            Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
            return;
        }
        //validate to_addr
        if (!to_addr.startsWith("0x") || to_addr.length() != 42) {
            Toast.makeText(context, "Recipient address is not valid; length is " + to_addr.length(),
                    Toast.LENGTH_LONG).show();
            return;
        }
        if (to_addr.equals(acct_addr)) {
            Toast.makeText(context, "Recipient cannot be the same as your account address", Toast.LENGTH_LONG)
                    .show();
            return;
        }
        EditText data_view = (EditText) findViewById(R.id.data);
        data = data_view.getText().toString();
        long size_wei = (long) (eth_size * WEI_PER_ETH);
        Payment_Processor.send(this, context, "", to_addr, size_wei, gas_limit, data.getBytes(), false);
        send_is_done = true;
        Button pay_view = (Button) findViewById(R.id.pay_button);
        pay_view.setClickable(false);
    }

    private void do_help(int title, int msg) {
        android.support.v7.app.AlertDialog.Builder alertDialogBuilder = new android.support.v7.app.AlertDialog.Builder(
                context);
        alertDialogBuilder.setTitle(getResources().getString(title));
        alertDialogBuilder.setMessage(getResources().getString(msg));
        alertDialogBuilder.setCancelable(false);
        alertDialogBuilder.setNeutralButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });
        android.support.v7.app.AlertDialog alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }

    //is is the callback from Payment_Processor
    public boolean payment_result(boolean ok, String txid, long size_wei, String client_data, String error) {
        this.txid = txid;
        dsp_txid_and_exit();
        return true;
    }

    public void interim_payment_result(long size_wei, String client_data, String msg) {
        if (toast != null)
            toast.cancel();
        (toast = Toast.makeText(context, "processing", Toast.LENGTH_LONG)).show();
    }

    public void balance_result(boolean ok, long balance, String error) {
        System.out.println("SendActivity:balance_result: Hey! we should never be here!");
    }

    public void interim_balance_result(String msg) {
        System.out.println("SendActivity:interim_result: Hey! we should never be here!");
    }

}