com.bringcommunications.etherpay.HistoryActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.bringcommunications.etherpay.HistoryActivity.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.app.ListActivity;
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.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ListView;
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 java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

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

public class HistoryActivity extends AppCompatActivity implements HTTP_Query_Client {
    //not: extends ListActivity
    private FrameLayout overlay_frame_layout;
    private HistoryActivity context;
    private static final float WEI_PER_ETH = (float) 1000000000000000000.0;
    private static final int GAS_LIMIT = 35000;
    private SharedPreferences preferences;
    private ListView list_view;
    List<Transaction_Info> transaction_list = null;
    private int total_transactions_processed = 0;
    private Toast toast = null;

    //inputs
    private String acct_addr = "";
    private boolean show_sent = true;
    private boolean show_received = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        overlay_frame_layout = new FrameLayout(getApplicationContext());
        setContentView(overlay_frame_layout);
        View activity_history_view = getLayoutInflater().inflate(R.layout.activity_history, overlay_frame_layout,
                false);
        setContentView(activity_history_view);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        //The internal implementation of the support library just checks if the Toolbar has a title (not null) at the moment the SupportActionBar is
        //set up. If there is, then this title will be used instead of the window title. You can then set a dummy title while you load the real title.
        toolbar.setTitle("");
        toolbar.setBackgroundResource(R.color.color_toolbar);
        setSupportActionBar(toolbar);
        //
        context = this;
        String app_uri = getResources().getString(R.string.app_uri);
        preferences = getSharedPreferences(app_uri, MODE_PRIVATE);
        acct_addr = preferences.getString("acct_addr", acct_addr);
        show_sent = getIntent().getBooleanExtra("SHOW_SENT", false);
        show_received = getIntent().getBooleanExtra("SHOW_RECEIVED", false);
        (toast = Toast.makeText(context, "retrieving transactions...", Toast.LENGTH_LONG)).show();
        String app_name = getResources().getString(R.string.app_name);
        toolbar.setTitle(app_name);
        toolbar.setSubtitle(show_sent ? "Payments Sent" : "Payments Received");
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        //no options menu
        return (false);
    }

    public void onResume() {
        super.onResume(); // Always call the superclass method first
        total_transactions_processed = 0;
        get_transactions(0);
    }

    //returns number of transactions processed (not number added to list)
    private int set_transactions(String rsp) {
        //typical response id:
        //{
        //  "status": 1,
        //  "data": [
        //    {
        //      "hash": "0x1b3dca103e0605b45f81eede754401df4082b87c4faf3f1205755b36f1b34ddf",
        //      "sender": "0x8b8a571730b631f58e7965d78582eae1b0417ab6",
        //      "recipient": "0x85d9147b0ec6d60390c8897244d039fb55b087c6",
        //      "accountNonce": "76",
        //      "price": 25000000000,
        //      "gasLimit": 35000,
        //      "amount": 2000000108199936,
        //      "block_id": 2721132,
        //      "time": "2016-11-30T09:58:07.000Z",
        //      "newContract": 0,
        //      "isContractTx": null,
        //      "blockHash": "0x5c1118c94176902cab1783f8d4f8d17544c7a16c8ef377f674fa89693eb3ab0c",
        //      "parentHash": "0x1b3dca103e0605b45f81eede754401df4082b87c4faf3f1205755b36f1b34ddf",
        //      "txIndex": null,
        //      "gasUsed": 21000,
        //      "type": "tx"
        //      },
        //      .....
        //   }
        int idx = 0;
        int status = 0;
        int no_transactions = 0;
        if (rsp.contains("status")) {
            int field_idx = rsp.indexOf("status") + "status".length();
            int beg_idx = rsp.indexOf(':', field_idx) + 1;
            int end_idx = rsp.indexOf(',', beg_idx);
            status = Integer.valueOf(rsp.substring(beg_idx, end_idx).trim());
            idx = end_idx + 1;
        }
        if (status != 1) {
            Util.show_err(getBaseContext(), "error retrieving transactions!", 3);
            Util.show_err(getBaseContext(), rsp.substring(0, 30), 10);
            return (0);
        }
        rsp = rsp.substring(idx);
        idx = 0;
        for (int i = 0; i < 100; ++i) {
            if (rsp.contains("{")) {
                idx = rsp.indexOf('{') + 1;
                rsp = rsp.substring(idx);
            } else {
                break;
            }
            ++no_transactions;
            String txid = "";
            String from = "";
            String to = "";
            long nonce = 0;
            float size = 0;
            Calendar date = Calendar.getInstance();
            if (rsp.contains("hash")) {
                int field_idx = rsp.indexOf("hash") + "hash".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                txid = rsp.substring(beg_idx, end_idx).replaceAll("\"", "").trim();
            }
            if (rsp.contains("sender")) {
                int field_idx = rsp.indexOf("sender") + "sender".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                from = rsp.substring(beg_idx, end_idx).replace("\"", "").trim();
                if (!show_sent && from.equals(acct_addr))
                    continue;
            }
            if (rsp.contains("recipient")) {
                int field_idx = rsp.indexOf("recipient") + "recipient".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                to = rsp.substring(beg_idx, end_idx).replace("\"", "").trim();
                if (!show_received && to.equals(acct_addr))
                    continue;
            }
            if (rsp.contains("accountNonce")) {
                int field_idx = rsp.indexOf("accountNonce") + "accountNonce".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                nonce = Long.valueOf(rsp.substring(beg_idx, end_idx).replace("\"", "").trim());
            }
            if (rsp.contains("amount")) {
                int field_idx = rsp.indexOf("amount") + "amount".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                long wei_amount = Long.valueOf(rsp.substring(beg_idx, end_idx).trim());
                size = wei_amount / WEI_PER_ETH;
            }
            if (rsp.contains("time")) {
                int field_idx = rsp.indexOf("time") + "time".length();
                int beg_idx = rsp.indexOf(':', field_idx) + 1;
                int end_idx = rsp.indexOf(',', beg_idx);
                String date_str = rsp.substring(beg_idx, end_idx).replace("\"", "").trim();
                //System.out.println("raw date: " + created_at);
                //could the date string have more or less than 3 digits after the decimal? (eg 5: 2015-11-10T01:20:14.16525Z). to avoid
                //complication, (and parse exceotions) we always force 3.
                int decimal_idx = date_str.indexOf(".");
                String conforming_date_str = date_str;
                if (decimal_idx < 0)
                    System.out.println("hey! no decimal in date string: " + conforming_date_str);
                if (decimal_idx >= 0) {
                    //decimal_idx is idx of decimal point. add 1 to get len, and we need 3 more digits (followed by 'Z')
                    if (date_str.length() >= decimal_idx + 5)
                        //substring includes end_idx -1
                        conforming_date_str = date_str.substring(0, decimal_idx + 4) + "Z";
                    else
                        conforming_date_str = date_str.substring(0, decimal_idx) + ".000Z";
                }
                //in java 7, an 'X' in the dateformat indicates that the date string might contain an ISO8601 suffix, eg. Z for UTC.
                //unfortunately that doesn't work for android. a 'Z' in the dateformat indicates that the timezone conforms to the RFC822
                //time zone standard, e.g. -0800. so we'll just convert to that.
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                conforming_date_str = conforming_date_str.replaceAll("Z$", "+0000");
                try {
                    date.setTime(df.parse(conforming_date_str));
                } catch (ParseException e) {
                    System.out.println(e.toString());
                }
            }
            Transaction_Info transaction_info = new Transaction_Info(txid, to, from, nonce, size, date);
            transaction_list.add(transaction_info);
            if (rsp.contains("}")) {
                idx = rsp.indexOf('}') + 1;
                rsp = rsp.substring(idx);
            } else {
                break;
            }
        }
        return (no_transactions);
    }

    public void handle_http_rsp(String callback, String rsp) {
        if (callback.equals("transactions")) {
            int processed = set_transactions(rsp);
            total_transactions_processed += processed;
            if ((processed) >= 50) {
                System.out.println(processed + " transaction processed; cur size is " + transaction_list.size());
                if (toast != null)
                    toast.cancel();
                (toast = Toast.makeText(context, "retrieving " + total_transactions_processed + " transactions...",
                        Toast.LENGTH_LONG)).show();
                get_transactions(total_transactions_processed);
            } else {
                Transaction_Info values[] = transaction_list.toArray(new Transaction_Info[transaction_list.size()]);
                list_view = (ListView) findViewById(R.id.listview);
                Transaction_Array_Adapter transaction_array_adapter = new Transaction_Array_Adapter(context, values,
                        acct_addr);
                list_view.setAdapter(transaction_array_adapter);
                /*
                list_view.setOnItemClickListener(new AdapterView.OnItemClickListener()
                {
                @Override
                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3)
                {
                    //args2 is the listViews Selected index
                  }
                });
                */
                //in case the "retrieving transactions" message is still showing
                if (toast != null)
                    toast.cancel();
            }
            return;
        }
    }

    //offset is the current nonce minus the index of the starting (most recent) transaction. for example, if the current nonce of the
    //most recent transaction is 77, then to get transactions with nonces from 77 to 28, pass offset "0". to get transactions with
    //nonces 76 to 27, pass offset "1"
    private void get_transactions(int offset) {
        if (offset == 0)
            transaction_list = new ArrayList<Transaction_Info>();
        String transactions_URL = "https://etherchain.org/api/account/" + acct_addr + "/tx/" + offset;
        String parms[] = new String[2];
        parms[0] = transactions_URL;
        parms[1] = "transactions";
        new HTTP_Query_Task(this, context).execute(parms);
    }

}