public class AddressDetailActivity extends SecureAppCompatActivity {

    public static final byte OWN_WALLET = 0;
    public static final byte SCANNED_WALLET = 1;

    private SectionsPagerAdapter mSectionsPagerAdapter;
    private ViewPager mViewPager;
    private Fragment[] fragments;
    private String address;
    private byte type;
    private TextView title;
    private CoordinatorLayout coord;
    private AppBarLayout appbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        address = getIntent().getStringExtra("ADDRESS");
        type = getIntent().getByteExtra("TYPE", SCANNED_WALLET);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        title = (TextView) findViewById(R.id.toolbar_title);
        String walletname = AddressNameConverter.getInstance(this).get(address);
        title.setText(type == OWN_WALLET ? (walletname == null ? "Unnamed Wallet" : walletname) : "Address");

        coord = (CoordinatorLayout) findViewById(R.id.main_content);
        appbar = (AppBarLayout) findViewById(R.id.appbar);

        fragments = new Fragment[3];
        fragments[0] = new FragmentDetailShare();
        fragments[1] = new FragmentDetailOverview();
        fragments[2] = new FragmentTransactions();
        Bundle bundle = new Bundle();
        bundle.putString("ADDRESS", address);
        bundle.putDouble("BALANCE", getIntent().getDoubleExtra("BALANCE", 0));
        bundle.putByte("TYPE", type);
        fragments[0].setArguments(bundle);
        fragments[1].setArguments(bundle);
        fragments[2].setArguments(bundle);

        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        mViewPager = (ViewPager) findViewById(R.id.container);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(mViewPager);
        tabLayout.setupWithViewPager(mViewPager);

        tabLayout.getTabAt(0).setIcon(R.drawable.ic_action_share);
        tabLayout.getTabAt(1).setIcon(R.drawable.ic_wallet);
        tabLayout.getTabAt(2).setIcon(R.drawable.ic_transactions);
        mViewPager.setCurrentItem(1);

        mViewPager.setOffscreenPageLimit(3);
    }

    public void setTitle(String s) {
        if (title != null) {
            title.setText(s);
            Snackbar mySnackbar = Snackbar.make(coord,
                    AddressDetailActivity.this.getResources().getString(R.string.detail_acc_name_changed_suc), Snackbar.LENGTH_SHORT);
            mySnackbar.show();
        }
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }

    public void snackError(String s) {
        if (coord == null) return;
        Snackbar mySnackbar = Snackbar.make(coord, s, Snackbar.LENGTH_SHORT);
        mySnackbar.show();
    }

    public void broadCastDataSetChanged() {
        if (fragments != null && fragments[2] != null) {
            ((FragmentTransactions) fragments[2]).notifyDataSetChanged();
        }
    }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return fragments[position];
        }

        @Override
        public int getCount() {
            return fragments.length;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return "";
        }
    }

    public AppBarLayout getAppBar() {
        return appbar;
    }

} public class SendActivity extends SecureAppCompatActivity {

    public static final int REQUEST_CODE = 200;

    private NonSwipeViewPager mViewPager;
    private Fragment[] fragments;

    private TextView title;
    private CoordinatorLayout coord;
    FragmentAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chooserecepient);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        title = (TextView) findViewById(R.id.toolbar_title);

        coord = (CoordinatorLayout) findViewById(R.id.main_content);

        fragments = new Fragment[2];
        fragments[0] = new FragmentChooseRecipient();
        fragments[1] = new FragmentSend();
        Bundle bundle = new Bundle();

        if (getIntent().hasExtra("TO_ADDRESS"))
            bundle.putString("TO_ADDRESS", getIntent().getStringExtra("TO_ADDRESS"));
        if (getIntent().hasExtra("AMOUNT"))
            bundle.putString("AMOUNT", getIntent().getStringExtra("AMOUNT"));
        if (getIntent().hasExtra("FROM_ADDRESS"))
            bundle.putString("FROM_ADDRESS", getIntent().getStringExtra("FROM_ADDRESS"));

        fragments[1].setArguments(bundle);

        adapter = new FragmentAdapter(getSupportFragmentManager());

        mViewPager = (NonSwipeViewPager) findViewById(R.id.container);
        mViewPager.setPagingEnabled(false);
        mViewPager.setAdapter(adapter);

        if (getIntent().hasExtra("TO_ADDRESS"))
            mViewPager.setCurrentItem(1);
    }


    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == QRScanActivity.REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                if (fragments == null || fragments[0] == null) return;
                ((FragmentChooseRecipient) fragments[0]).setRecipientAddress(data.getStringExtra("ADDRESS"));
            } else {
                Snackbar mySnackbar = Snackbar.make(coord,
                        this.getResources().getString(R.string.main_ac_wallet_added_fatal), Snackbar.LENGTH_SHORT);
                mySnackbar.show();
            }
        }
    }

    public void nextStage(String toAddress) {
        mViewPager.setCurrentItem(1);

        if (fragments == null || fragments[1] == null) return;
        ((FragmentSend) fragments[1]).setToAddress(toAddress, this);
    }


    class FragmentAdapter extends FragmentPagerAdapter {

        private FragmentManager mFragmentManager;

        public FragmentAdapter(FragmentManager fm) {
            super(fm);
            mFragmentManager = fm;
        }

        @Override
        public Fragment getItem(int position) {
            return fragments[position];
        }

        @Override
        public int getCount() {
            return 2;
        }
    }

    public void setTitle(String s) {
        if (title != null) {
            title.setText(s);
            Snackbar mySnackbar = Snackbar.make(coord,
                    SendActivity.this.getResources().getString(R.string.detail_acc_name_changed_suc), Snackbar.LENGTH_SHORT);
            mySnackbar.show();
        }
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }

    public void snackError(String s, int length) {
        if (coord == null) return;
        Snackbar mySnackbar = Snackbar.make(coord, s, length);
        mySnackbar.show();
    }

    public void snackError(String s) {
        snackError(s, Snackbar.LENGTH_SHORT);
    }

} public class CurrencyEntry {

    private String name;
    private double rate;
    private String shorty;

    public CurrencyEntry(String name, double rate, String shorty) {
        this.name = name;
        this.rate = rate;
        this.shorty = shorty;
    }

    public String getShorty() {
        return shorty;
    }

    public void setShorty(String shorty) {
        this.shorty = shorty;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }
} public class TokenDisplay implements Comparable {

    private String name;
    private String shorty;
    private BigDecimal balance;
    private int digits;
    private double usdprice;
    private String contractAddr;
    private String totalSupply;
    private long holderCount;
    private long createdAt;

    public TokenDisplay(String name, String shorty, BigDecimal balance, int digits, double usdprice, String contractAddr, String totalSupply, long holderCount, long createdAt) {
        this.name = name;
        this.shorty = shorty;
        this.balance = balance;
        this.digits = digits;
        this.usdprice = usdprice;
        this.contractAddr = contractAddr;
        this.totalSupply = totalSupply;
        this.holderCount = holderCount;
        this.createdAt = createdAt;
    }

    public long getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(long createdAt) {
        this.createdAt = createdAt;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getShorty() {
        return shorty;
    }

    public void setShorty(String shorty) {
        this.shorty = shorty;
    }

    public BigDecimal getBalance() {
        return balance;
    }

    /**
     * Uses digits and balance to create a double value
     *
     * @return Token balance in double
     */
    public double getBalanceDouble() {
        return balance.divide((new BigDecimal("10").pow(digits))).doubleValue();
    }

    /**
     * Uses digits and total supply to create a long value
     *
     * @return Token supply in long
     */
    public long getTotalSupplyLong() {
        return new BigInteger(totalSupply).divide((new BigInteger("10").pow(digits))).longValue();
    }

    public void setBalance(BigDecimal balance) {
        this.balance = balance;
    }

    public int getDigits() {
        return digits;
    }

    public void setDigits(int digits) {
        this.digits = digits;
    }

    public double getUsdprice() {
        return usdprice;
    }

    public void setUsdprice(double usdprice) {
        this.usdprice = usdprice;
    }

    public String getContractAddr() {
        return contractAddr;
    }

    public void setContractAddr(String contractAddr) {
        this.contractAddr = contractAddr;
    }

    public String getTotalSupply() {
        return totalSupply;
    }

    public void setTotalSupply(String totalSupply) {
        this.totalSupply = totalSupply;
    }

    public long getHolderCount() {
        return holderCount;
    }

    public void setHolderCount(long holderCount) {
        this.holderCount = holderCount;
    }

    @Override
    public int compareTo(@NonNull Object o) {
        return ((TokenDisplay) o).getShorty().compareTo(shorty);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        TokenDisplay that = (TokenDisplay) o;

        if (digits != that.digits) return false;
        if (!name.equals(that.name)) return false;
        return shorty.equals(that.shorty);

    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + shorty.hashCode();
        result = 31 * result + digits;
        return result;
    }
} public class WatchWallet implements StorableWallet, Serializable {

    private static final long serialVersionUID = -146500951598835658L;
    private String pubKey;
    private long dateAdded;

    public WatchWallet(String pubKey) {
        this.pubKey = pubKey.toLowerCase();
        this.dateAdded = System.currentTimeMillis();
    }

    public String getPubKey() {
        return pubKey;
    }

    public void setPubKey(String pubKey) {
        this.pubKey = pubKey;
    }

    public long getDateAdded() {
        return dateAdded;
    }

    public void setDateAdded(long dateAdded) {
        this.dateAdded = dateAdded;
    }
} public interface LastIconLoaded {

    public void onLastIconDownloaded();
} public class EtherscanAPI {

    private String token;

    private static EtherscanAPI instance;

    public static EtherscanAPI getInstance() {
        if (instance == null)
            instance = new EtherscanAPI();
        return instance;
    }

    public void getPriceChart(long starttime, int period, boolean usd, Callback b) throws IOException {
        get("https://poloniex.com/public?command=returnChartData&currencyPair=" + (usd ? "USDT_ETH" : "BTC_ETH") + "&start=" + starttime + "&end=9999999999&period=" + period, b);
    }


    /**
     * Retrieve all internal transactions from address like contract calls, for normal transactions @see rehanced.com.simpleetherwallet.network.EtherscanAPI#getNormalTransactions() )
     *
     * @param address Ether address
     * @param b       Network callback to @see rehanced.com.simpleetherwallet.fragments.FragmentTransactions#update() or @see rehanced.com.simpleetherwallet.fragments.FragmentTransactionsAll#update()
     * @param force   Whether to force (true) a network call or use cache (false). Only true if user uses swiperefreshlayout
     * @throws IOException Network exceptions
     */
    public void getInternalTransactions(String address, Callback b, boolean force) throws IOException {
        if (!force && RequestCache.getInstance().contains(RequestCache.TYPE_TXS_INTERNAL, address)) {
            b.onResponse(null, new Response.Builder().code(200).message("").request(new Request.Builder()
                    .url("https://api.etherscan.io/api?module=account&action=txlistinternal&address=" + address + "&startblock=0&endblock=99999999&sort=asc&apikey=" + token)
                    .build()).protocol(Protocol.HTTP_1_0).body(ResponseBody.create(MediaType.parse("JSON"), RequestCache.getInstance().get(RequestCache.TYPE_TXS_INTERNAL, address))).build());
            return;
        }
        get("https://api.etherscan.io/api?module=account&action=txlistinternal&address=" + address + "&startblock=0&endblock=99999999&sort=asc&apikey=" + token, b);
    }


    /**
     * Retrieve all normal ether transactions from address (excluding contract calls etc, @see rehanced.com.simpleetherwallet.network.EtherscanAPI#getInternalTransactions() )
     *
     * @param address Ether address
     * @param b       Network callback to @see rehanced.com.simpleetherwallet.fragments.FragmentTransactions#update() or @see rehanced.com.simpleetherwallet.fragments.FragmentTransactionsAll#update()
     * @param force   Whether to force (true) a network call or use cache (false). Only true if user uses swiperefreshlayout
     * @throws IOException Network exceptions
     */
    public void getNormalTransactions(String address, Callback b, boolean force) throws IOException {
        if (!force && RequestCache.getInstance().contains(RequestCache.TYPE_TXS_NORMAL, address)) {
            b.onResponse(null, new Response.Builder().code(200).message("").request(new Request.Builder()
                    .url("https://api.etherscan.io/api?module=account&action=txlist&address=" + address + "&startblock=0&endblock=99999999&sort=asc&apikey=" + token)
                    .build()).protocol(Protocol.HTTP_1_0).body(ResponseBody.create(MediaType.parse("JSON"), RequestCache.getInstance().get(RequestCache.TYPE_TXS_NORMAL, address))).build());
            return;
        }
        get("https://api.etherscan.io/api?module=account&action=txlist&address=" + address + "&startblock=0&endblock=99999999&sort=asc&apikey=" + token, b);
    }


    public void getEtherPrice(Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=stats&action=ethprice&apikey=" + token, b);
    }


    public void getGasPrice(Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=proxy&action=eth_gasPrice&apikey=" + token, b);
    }


    /**
     * Get token balances via ethplorer.io
     *
     * @param address Ether address
     * @param b       Network callback to @see rehanced.com.simpleetherwallet.fragments.FragmentDetailOverview#update()
     * @param force   Whether to force (true) a network call or use cache (false). Only true if user uses swiperefreshlayout
     * @throws IOException Network exceptions
     */
    public void getTokenBalances(String address, Callback b, boolean force) throws IOException {
        if (!force && RequestCache.getInstance().contains(RequestCache.TYPE_TOKEN, address)) {
            b.onResponse(null, new Response.Builder().code(200).message("").request(new Request.Builder()
                    .url("https://api.ethplorer.io/getAddressInfo/" + address + "?apiKey=freekey")
                    .build()).protocol(Protocol.HTTP_1_0).body(ResponseBody.create(MediaType.parse("JSON"), RequestCache.getInstance().get(RequestCache.TYPE_TOKEN, address))).build());
            return;
        }
        get("https://api.ethplorer.io/getAddressInfo/" + address + "?apiKey=freekey", b);
    }


    /**
     * Download and save token icon in permanent image cache (TokenIconCache)
     *
     * @param c         Application context, used to load TokenIconCache if reinstanced
     * @param tokenName Name of token
     * @param lastToken Boolean defining whether this is the last icon to download or not. If so callback is called to refresh recyclerview (notifyDataSetChanged)
     * @param callback  Callback to @see rehanced.com.simpleetherwallet.fragments.FragmentDetailOverview#onLastIconDownloaded()
     * @throws IOException Network exceptions
     */
    public void loadTokenIcon(final Context c, String tokenName, final boolean lastToken, final LastIconLoaded callback) throws IOException {
        if (tokenName.indexOf(" ") > 0)
            tokenName = tokenName.substring(0, tokenName.indexOf(" "));
        if (TokenIconCache.getInstance(c).contains(tokenName)) return;

        if(tokenName.equalsIgnoreCase("OMGToken"))
            tokenName = "omise";
        else if(tokenName.equalsIgnoreCase("0x"))
            tokenName = "0xtoken_28";

        final String tokenNamef = tokenName;
        get("https://etherscan.io//token/images/" + tokenNamef + ".PNG", new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (c == null) return;
                ResponseBody in = response.body();
                InputStream inputStream = in.byteStream();
                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                final Bitmap bitmap = BitmapFactory.decodeStream(bufferedInputStream);
                TokenIconCache.getInstance(c).put(c, tokenNamef, new BitmapDrawable(c.getResources(), bitmap).getBitmap());
                // if(lastToken) // TODO: resolve race condition
                callback.onLastIconDownloaded();
            }
        });
    }


    public void getGasLimitEstimate(String to, Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=proxy&action=eth_estimateGas&to=" + to + "&value=0xff22&gasPrice=0x051da038cc&gas=0xffffff&apikey=" + token, b);
    }


    public void getBalance(String address, Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=account&action=balance&address=" + address + "&apikey=" + token, b);
    }


    public void getNonceForAddress(String address, Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=proxy&action=eth_getTransactionCount&address=" + address + "&tag=latest&apikey=" + token, b);
    }


    /**
     * Guys please don't abuse this key. I put this release together in the middle of the night, migrating some third party api
     * changes and don't want to bother with obfuscating this key.
     * It's a free plan, limited to 10k requests and is intended for Lunary users only.
     * Please be fair and don't missuse this key. If not for my sake but the the sake of those users.
     * @param b
     * @throws IOException
     */
    public void getPriceConversionRates(Callback b) throws IOException {
        get("http://data.fixer.io/api/latest?access_key=6731fb62377f28c429b246c2184a6a46", b);
    }

    public void getBalances(ArrayList<StorableWallet> addresses, Callback b) throws IOException {
        String url = "https://api.etherscan.io/api?module=account&action=balancemulti&address=";
        for (StorableWallet address : addresses)
            url += address.getPubKey() + ",";
        url = url.substring(0, url.length() - 1) + "&tag=latest&apikey=" + token; // remove last , AND add token
        get(url, b);
    }


    public void forwardTransaction(String raw, Callback b) throws IOException {
        get("https://api.etherscan.io/api?module=proxy&action=eth_sendRawTransaction&hex=" + raw + "&apikey=" + token, b);
    }


    public void get(String url, Callback b) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .build();

        client.newCall(request).enqueue(b);
    }


    private EtherscanAPI() {
        token = new Key(APIKey.API_KEY).toString();
    }

} public class AddressNameConverter {

    private HashMap<String, String> addressbook;
    private HashMap<String, String> wellknown_addresses;
    private static AddressNameConverter instance;

    public static AddressNameConverter getInstance(Context context) {
        if (instance == null)
            instance = new AddressNameConverter(context);
        return instance;
    }

    private AddressNameConverter(Context context) {
        try {
            load(context);
            if (!contains("0xa9981a33f6b1a18da5db58148b2357f22b44e1e0")) {
                put("0xa9981a33f6b1a18da5db58148b2357f22b44e1e0", "Lunary Development ✓", context);
            }
        } catch (Exception e) {
            addressbook = new HashMap<String, String>();
            put("0xa9981a33f6b1a18da5db58148b2357f22b44e1e0", "Lunary Development ✓", context);
        }
        wellknown_addresses = new WellKnownAddresses();
    }

    public synchronized void put(String addresse, String name, Context context) {
        if (name == null || name.length() == 0)
            addressbook.remove(addresse);
        else
            addressbook.put(addresse, name.length() > 22 ? name.substring(0, 22) : name);
        save(context);
    }

    public String get(String addresse) {
        return addressbook.get(addresse);
    }

    public boolean contains(String addresse) {
        return addressbook.containsKey(addresse);
    }

    public ArrayList<WalletDisplay> getAsAddressbook() {
        ArrayList<WalletDisplay> erg = new ArrayList<WalletDisplay>();
        for (Map.Entry<String, String> entry : addressbook.entrySet()) {
            erg.add(new WalletDisplay(entry.getValue().toString(), entry.getKey().toString()));
        }
        Collections.sort(erg);
        return erg;
    }

    public synchronized void save(Context context) {
        FileOutputStream fout;
        try {
            fout = new FileOutputStream(new File(context.getFilesDir(), "namedb.dat"));
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject(addressbook);
            oos.close();
            fout.close();
        } catch (Exception e) {
        }
    }

    @SuppressWarnings("unchecked")
    public synchronized void load(Context context) throws IOException, ClassNotFoundException {
        FileInputStream fout = new FileInputStream(new File(context.getFilesDir(), "namedb.dat"));
        ObjectInputStream oos = new ObjectInputStream(new BufferedInputStream(fout));
        addressbook = (HashMap<String, String>) oos.readObject();
        oos.close();
        fout.close();
    }

} public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {

    public enum State {
        EXPANDED,
        COLLAPSED,
        IDLE
    }

    private State mCurrentState = State.IDLE;

    @Override
    public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        if (i == 0) {
            if (mCurrentState != State.EXPANDED) {
                onStateChanged(appBarLayout, State.EXPANDED);
            }
            mCurrentState = State.EXPANDED;
        } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
            if (mCurrentState != State.COLLAPSED) {
                onStateChanged(appBarLayout, State.COLLAPSED);
            }
            mCurrentState = State.COLLAPSED;
        } else {
            if (mCurrentState != State.IDLE) {
                onStateChanged(appBarLayout, State.IDLE);
            }
            mCurrentState = State.IDLE;
        }
    }

    public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
} public class Blockies {

    private static final int size = 8;
    private static long[] randseed = new long[4];

    public static Bitmap createIcon(String address) {
        return createIcon(address, 16);
    }

    public static Bitmap createIcon(String address, int scale) {
        seedrand(address);
        HSL color = createColor();
        HSL bgColor = createColor();
        HSL spotColor = createColor();

        double[] imgdata = createImageData();
        return createCanvas(imgdata, color, bgColor, spotColor, scale);
    }

    private static Bitmap createCanvas(double[] imgData, HSL color, HSL bgcolor, HSL spotcolor, int scale) {
        int width = (int) Math.sqrt(imgData.length);

        int w = width * scale;
        int h = width * scale;

        Bitmap.Config conf = Bitmap.Config.ARGB_8888;
        Bitmap bmp = Bitmap.createBitmap(w, h, conf);
        Canvas canvas = new Canvas(bmp);

        int background = toRGB((int) bgcolor.h, (int) bgcolor.s, (int) bgcolor.l);

        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(background);
        canvas.drawRect(0, 0, w, h, paint);

        int main = toRGB((int) color.h, (int) color.s, (int) color.l);
        int scolor = toRGB((int) spotcolor.h, (int) spotcolor.s, (int) spotcolor.l);

        for (int i = 0; i < imgData.length; i++) {
            int row = (int) Math.floor(i / width);
            int col = i % width;
            paint = new Paint();

            paint.setColor((imgData[i] == 1.0d) ? main : scolor);

            if (imgData[i] > 0d) {
                canvas.drawRect(col * scale, row * scale, (col * scale) + scale, (row * scale) + scale, paint);
            }
        }
        return getCroppedBitmap(bmp);
    }

    private static double rand() {
        int t = (int) (randseed[0] ^ (randseed[0] << 11));
        randseed[0] = randseed[1];
        randseed[1] = randseed[2];
        randseed[2] = randseed[3];
        randseed[3] = (randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8));
        double t1 = Math.abs(randseed[3]);

        return (t1 / Integer.MAX_VALUE);
    }

    private static HSL createColor() {
        double h = Math.floor(rand() * 360d);
        double s = ((rand() * 60d) + 40d);
        double l = ((rand() + rand() + rand() + rand()) * 25d);
        return new HSL(h, s, l);
    }

    private static double[] createImageData() {
        int width = size;
        int height = size;

        double dataWidth = Math.ceil(width / 2);
        double mirrorWidth = width - dataWidth;

        double[] data = new double[size * size];
        int dataCount = 0;
        for (int y = 0; y < height; y++) {
            double[] row = new double[(int) dataWidth];
            for (int x = 0; x < dataWidth; x++) {
                row[x] = Math.floor(rand() * 2.3d);

            }
            double[] r = Arrays.copyOfRange(row, 0, (int) mirrorWidth);
            r = reverse(r);
            row = concat(row, r);

            for (int i = 0; i < row.length; i++) {
                data[dataCount] = row[i];
                dataCount++;
            }
        }

        return data;
    }

    public static double[] concat(double[] a, double[] b) {
        int aLen = a.length;
        int bLen = b.length;
        double[] c = new double[aLen + bLen];
        System.arraycopy(a, 0, c, 0, aLen);
        System.arraycopy(b, 0, c, aLen, bLen);
        return c;
    }

    private static double[] reverse(double[] data) {
        for (int i = 0; i < data.length / 2; i++) {
            double temp = data[i];
            data[i] = data[data.length - i - 1];
            data[data.length - i - 1] = temp;
        }
        return data;
    }

    private static void seedrand(String seed) {
        for (int i = 0; i < randseed.length; i++) {
            randseed[i] = 0;
        }
        for (int i = 0; i < seed.length(); i++) {
            long test = randseed[i % 4] << 5;
            if (test > Integer.MAX_VALUE << 1 || test < Integer.MIN_VALUE << 1)
                test = (int) test;

            long test2 = test - randseed[i % 4];
            randseed[i % 4] = (test2 + Character.codePointAt(seed, i));
        }

        for (int i = 0; i < randseed.length; i++)
            randseed[i] = (int) randseed[i];
    }

    private static int toRGB(float h, float s, float l) {
        h = h % 360.0f;
        h /= 360f;
        s /= 100f;
        l /= 100f;

        float q = 0;

        if (l < 0.5)
            q = l * (1 + s);
        else
            q = (l + s) - (s * l);

        float p = 2 * l - q;

        float r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)));
        float g = Math.max(0, HueToRGB(p, q, h));
        float b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)));

        r = Math.min(r, 1.0f);
        g = Math.min(g, 1.0f);
        b = Math.min(b, 1.0f);

        int red = (int) (r * 255);
        int green = (int) (g * 255);
        int blue = (int) (b * 255);
        return Color.rgb(red, green, blue);
    }

    private static float HueToRGB(float p, float q, float h) {
        if (h < 0) h += 1;
        if (h > 1) h -= 1;
        if (6 * h < 1) {
            return p + ((q - p) * 6 * h);
        }
        if (2 * h < 1) {
            return q;
        }
        if (3 * h < 2) {
            return p + ((q - p) * 6 * ((2.0f / 3.0f) - h));
        }
        return p;
    }

    public static Bitmap getCroppedBitmap(Bitmap bitmap) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
                bitmap.getWidth() / 2, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    static class HSL {
        double h, s, l;

        public HSL(double h, double s, double l) {
            this.h = h;
            this.s = s;
            this.l = l;
        }

        @Override
        public String toString() {
            return "HSL [h=" + h + ", s=" + s + ", l=" + l + "]";
        }

    }
} public class Dialogs {

    public static void askForPasswordAndDecode(Activity ac, final String fromAddress, final PasswordDialogCallback callback) {
        AlertDialog.Builder builder = new AlertDialog.Builder(ac, R.style.AlertDialogTheme);
        builder.setTitle("Wallet Password");

        final EditText input = new EditText(ac);
        final CheckBox showpw = new CheckBox(ac);
        showpw.setText(R.string.password_in_clear_text);
        input.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
        input.setTransformationMethod(PasswordTransformationMethod.getInstance());

        LinearLayout container = new LinearLayout(ac);
        container.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.leftMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.topMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.bottomMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.rightMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);

        LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params2.leftMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params2.rightMargin = ac.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        input.setLayoutParams(params);
        showpw.setLayoutParams(params2);

        container.addView(input);
        container.addView(showpw);
        builder.setView(container);

        showpw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (!isChecked)
                    input.setTransformationMethod(PasswordTransformationMethod.getInstance());
                else
                    input.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
                input.setSelection(input.getText().length());
            }
        });

        builder.setView(container);
        input.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    InputMethodManager inputMgr = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
                }
            }
        });
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                InputMethodManager inputMgr = (InputMethodManager) input.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMgr.hideSoftInputFromWindow(input.getWindowToken(), 0);
                callback.success(input.getText().toString());
                dialog.dismiss();
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                InputMethodManager inputMgr = (InputMethodManager) input.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMgr.hideSoftInputFromWindow(input.getWindowToken(), 0);
                callback.canceled();
                dialog.cancel();
            }
        });

        builder.show();

    }

    public static void showTokenetails(final Activity c, final TokenDisplay tok) {
        MaterialDialog dialog = new MaterialDialog.Builder(c)
                .customView(R.layout.dialog_token_detail, true)
                .show();
        View view = dialog.getCustomView();
        ImageView contractIcon = (ImageView) view.findViewById(R.id.my_addressicon);
        TextView tokenname = (TextView) view.findViewById(R.id.walletname);
        AutofitTextView contractAddr = (AutofitTextView) view.findViewById(R.id.walletaddr);

        TextView supply = (TextView) view.findViewById(R.id.supply);
        TextView priceUSD = (TextView) view.findViewById(R.id.price);
        TextView priceETH = (TextView) view.findViewById(R.id.price2);
        TextView capUSD = (TextView) view.findViewById(R.id.cap);
        TextView capETH = (TextView) view.findViewById(R.id.cap2);
        TextView holders = (TextView) view.findViewById(R.id.holders);
        TextView digits = (TextView) view.findViewById(R.id.digits);

        LinearLayout from = (LinearLayout) view.findViewById(R.id.from);

        from.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(c, AddressDetailActivity.class);
                i.putExtra("ADDRESS", tok.getContractAddr());
                c.startActivity(i);
            }
        });

        ExchangeCalculator ex = ExchangeCalculator.getInstance();
        contractIcon.setImageBitmap(Blockies.createIcon(tok.getContractAddr().toLowerCase()));
        tokenname.setText(tok.getName());
        contractAddr.setText(tok.getContractAddr().toLowerCase());
        supply.setText(ex.displayUsdNicely(tok.getTotalSupplyLong()) + " " + tok.getShorty());
        priceUSD.setText(tok.getUsdprice() + " $");

        priceETH.setText(ex.displayEthNicelyExact(
                ex.convertTokenToEther(1, tok.getUsdprice())
        ) + " " + ex.getEtherCurrency().getShorty());
        capETH.setText(ex.displayUsdNicely(
                ex.convertTokenToEther(tok.getTotalSupplyLong(), tok.getUsdprice())
        ) + " " + ex.getEtherCurrency().getShorty());
        capUSD.setText(ex.displayUsdNicely(tok.getUsdprice() * tok.getTotalSupplyLong()) + " $");
        holders.setText(ex.displayUsdNicely(tok.getHolderCount()) + "");
        digits.setText(tok.getDigits() + "");
    }

    public static void showTXDetails(final Activity c, final TransactionDisplay tx) {
        MaterialDialog dialog = new MaterialDialog.Builder(c)
                .customView(R.layout.dialog_tx_detail, true)
                .show();
        View view = dialog.getCustomView();
        ImageView myicon = (ImageView) view.findViewById(R.id.my_addressicon);
        ImageView othericon = (ImageView) view.findViewById(R.id.other_addressicon);
        TextView myAddressname = (TextView) view.findViewById(R.id.walletname);
        TextView otherAddressname = (TextView) view.findViewById(R.id.other_address);
        AutofitTextView myAddressaddr = (AutofitTextView) view.findViewById(R.id.walletaddr);
        AutofitTextView otherAddressaddr = (AutofitTextView) view.findViewById(R.id.other_addressaddr);
        TextView amount = (TextView) view.findViewById(R.id.amount);

        TextView month = (TextView) view.findViewById(R.id.month);
        TextView gasUsed = (TextView) view.findViewById(R.id.gasused);
        TextView blocknr = (TextView) view.findViewById(R.id.blocknr);
        TextView gasPrice = (TextView) view.findViewById(R.id.gasPrice);
        TextView nonce = (TextView) view.findViewById(R.id.nonce);
        TextView txcost = (TextView) view.findViewById(R.id.txcost);
        TextView txcost2 = (TextView) view.findViewById(R.id.txcost2);
        Button openInBrowser = (Button) view.findViewById(R.id.openinbrowser);
        LinearLayout from = (LinearLayout) view.findViewById(R.id.from);
        LinearLayout to = (LinearLayout) view.findViewById(R.id.to);
        TextView amountfiat = (TextView) view.findViewById(R.id.amountfiat);
        TextView errormsg = (TextView) view.findViewById(R.id.errormsg);

        from.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(c, AddressDetailActivity.class);
                i.putExtra("ADDRESS", tx.getFromAddress());
                c.startActivity(i);
            }
        });

        to.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(c, AddressDetailActivity.class);
                i.putExtra("ADDRESS", tx.getToAddress());
                c.startActivity(i);
            }
        });

        openInBrowser.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String url = "https://etherscan.io/tx/" + tx.getTxHash();
                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setData(Uri.parse(url));
                c.startActivity(i);
            }
        });

        myicon.setImageBitmap(Blockies.createIcon(tx.getFromAddress().toLowerCase()));
        othericon.setImageBitmap(Blockies.createIcon(tx.getToAddress().toLowerCase()));

        String myName = AddressNameConverter.getInstance(c).get(tx.getFromAddress().toLowerCase());
        if (myName == null) myName = shortName(tx.getFromAddress().toLowerCase());
        String otherName = AddressNameConverter.getInstance(c).get(tx.getToAddress().toLowerCase());
        if (otherName == null) otherName = shortName(tx.getToAddress().toLowerCase());
        myAddressname.setText(myName);
        otherAddressname.setText(otherName);

        errormsg.setVisibility(tx.isError() ? View.VISIBLE : View.GONE);
        myAddressaddr.setText(tx.getFromAddress());
        otherAddressaddr.setText(tx.getToAddress());
        SimpleDateFormat dateformat = new SimpleDateFormat("dd. MMMM yyyy, HH:mm:ss", Locale.getDefault());
        month.setText(dateformat.format(tx.getDate()) + "");
        blocknr.setText(tx.getBlock() + "");
        gasUsed.setText(tx.getGasUsed() + "");
        gasPrice.setText(tx.getGasprice() / 1000000000 + " Gwei");
        nonce.setText(tx.getNounce() + "");
        txcost.setText(
                ExchangeCalculator.getInstance().displayEthNicelyExact(
                        ExchangeCalculator.getInstance().weiToEther(tx.getGasUsed() * tx.getGasprice())
                )
                        + " Ξ"
        );
        txcost2.setText(
                ExchangeCalculator.getInstance().convertToUsd(ExchangeCalculator.getInstance().weiToEther(tx.getGasUsed() * tx.getGasprice()))
                        + " " + ExchangeCalculator.getInstance().getMainCurreny().getShorty()
        );
        amount.setText((tx.getAmount() > 0 ? "+ " : "- ") + Math.abs(tx.getAmount()) + " Ξ");
        amount.setTextColor(c.getResources().getColor(tx.getAmount() > 0 ? R.color.etherReceived : R.color.etherSpent));
        amountfiat.setText(ExchangeCalculator.getInstance().displayUsdNicely(
                ExchangeCalculator.getInstance().convertToUsd(tx.getAmount()))
                + " " + ExchangeCalculator.getInstance().getMainCurreny().getShorty());
    }

    private static String shortName(String addr) {
        return "0x" + addr.substring(2, 8);
    }

    public static void addWatchOnly(final MainActivity c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_watch_only_title);

        final EditText input = new EditText(c);
        input.setSingleLine();
        FrameLayout container = new FrameLayout(c);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.leftMargin = c.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.topMargin = c.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.bottomMargin = c.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        params.rightMargin = c.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
        input.setLayoutParams(params);

        input.setInputType(InputType.TYPE_CLASS_TEXT);
        container.addView(input);
        builder.setView(container);
        input.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    InputMethodManager inputMgr = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
                }
            }
        });
        builder.setNegativeButton(R.string.add, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                InputMethodManager inputMgr = (InputMethodManager) input.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMgr.hideSoftInputFromWindow(input.getWindowToken(), 0);
                if (input.getText().toString().length() == 42 && input.getText().toString().startsWith("0x")) {
                    final boolean suc = WalletStorage.getInstance(c).add(new WatchWallet(input.getText().toString()), c);
                    new Handler().postDelayed(
                            new Runnable() {
                                @Override
                                public void run() {
                                    if (c.fragments != null && c.fragments[1] != null) {
                                        try {
                                            ((FragmentWallets) c.fragments[1]).update();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                    c.snackError(c.getResources().getString(suc ? R.string.main_ac_wallet_added_suc : R.string.main_ac_wallet_added_er));
                                    if (suc)
                                        AddressNameConverter.getInstance(c).put(input.getText().toString(), "Watch " + input.getText().toString().substring(0, 6), c);
                                }
                            }, 100);
                } else {
                    c.snackError("Invalid Ethereum address!");
                }
                dialog.dismiss();
            }
        });
        builder.setPositiveButton(R.string.show, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                InputMethodManager inputMgr = (InputMethodManager) input.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMgr.hideSoftInputFromWindow(input.getWindowToken(), 0);
                if (input.getText().toString().length() == 42 && input.getText().toString().startsWith("0x")) {
                    Intent detail = new Intent(c, AddressDetailActivity.class);
                    detail.putExtra("ADDRESS", input.getText().toString().toLowerCase());
                    c.startActivity(detail);
                } else {
                    c.snackError("Invalid Ethereum address!");
                }
                dialog.cancel();
            }
        });
        builder.setNeutralButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                InputMethodManager inputMgr = (InputMethodManager) input.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                inputMgr.hideSoftInputFromWindow(input.getWindowToken(), 0);
                dialog.cancel();
            }
        });

        builder.show();

    }

    public static void writeDownPassword(final WalletGenActivity c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_write_down_pw_title);
        builder.setMessage(c.getString(R.string.dialog_write_down_pw_text));
        builder.setPositiveButton(R.string.action_sign_in, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                c.gen();
                dialog.cancel();
            }
        });
        builder.setNegativeButton(R.string.dialog_back_button, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        builder.show();
    }

    public static void importWallets(final MainActivity c, final ArrayList<File> files) {
        String addresses = "";
        for (int i = 0; i < files.size() && i < 3; i++)
            addresses += WalletStorage.stripWalletName(files.get(i).getName()) + "\n";

        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_importing_wallets_title);
        builder.setMessage(String.format(c.getString(R.string.dialog_importing_wallets_text), files.size(), files.size() > 1 ? "s" : "", addresses));
        builder.setPositiveButton(R.string.button_yes, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                try {
                    WalletStorage.getInstance(c).importWallets(c, files);
                    c.snackError("Wallet" + (files.size() > 1 ? "s" : "") + " successfully imported!");
                    if (c.fragments != null && c.fragments[1] != null)
                        ((FragmentWallets) c.fragments[1]).update();
                } catch (Exception e) {
                    c.snackError("Error while importing wallets");
                    e.printStackTrace();
                }
                dialog.cancel();
            }
        });
        builder.setNegativeButton(R.string.button_no, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        builder.show();
    }

    public static void adDisable(Context c, final AdDialogResponseHandler res) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_disable_ad_title);
        builder.setMessage(R.string.dialog_disable_ad_text);
        builder.setCancelable(false);
        builder.setPositiveButton(R.string.fragment_recipient_continue, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                res.continueSettingChange(true);
            }
        });
        builder.setNegativeButton(R.string.dialog_back_button, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                res.continueSettingChange(false);
            }
        });

        builder.show();
    }

    public static void cantExportNonWallet(Context c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_ex_nofull_title);
        builder.setMessage(R.string.dialog_ex_nofull_text);
        builder.setNeutralButton(R.string.button_ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        builder.show();
    }

    public static void exportWallet(Context c, DialogInterface.OnClickListener yes) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_exporting_title);
        builder.setMessage(R.string.dialog_exporting_text);
        builder.setPositiveButton(R.string.button_ok, yes);
        builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.show();
    }

    public static void noFullWallet(Context c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_nofullwallet);
        builder.setMessage(R.string.dialog_nofullwallet_text);
        builder.setNeutralButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        builder.show();
    }

    public static void noWallet(Context c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_no_wallets);
        builder.setMessage(R.string.dialog_no_wallets_text);
        builder.setNeutralButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        builder.show();
    }

    public static void noImportWalletsFound(Context c) {
        AlertDialog.Builder builder;
        if (Build.VERSION.SDK_INT >= 24) // Otherwise buttons on 7.0+ are nearly invisible
            builder = new AlertDialog.Builder(c, R.style.AlertDialogTheme);
        else
            builder = new AlertDialog.Builder(c);
        builder.setTitle(R.string.dialog_no_wallets_found);
        builder.setMessage(R.string.dialog_no_wallets_found_text);
        builder.setNeutralButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        builder.show();
    }
} public class ExchangeCalculator {

    public static final BigDecimal ONE_ETHER = new BigDecimal("1000000000000000000");

    private static ExchangeCalculator instance;
    private long lastUpdateTimestamp = 0;
    private double rateForChartDisplay = 1;
    private DecimalFormat formatterUsd = new DecimalFormat("#,###,###.##");
    private DecimalFormat formatterCrypt = new DecimalFormat("#,###,###.####");
    private DecimalFormat formatterCryptExact = new DecimalFormat("#,###,###.#######");

    private ExchangeCalculator() {
    }

    public static ExchangeCalculator getInstance() {
        if (instance == null)
            instance = new ExchangeCalculator();
        return instance;
    }

    private CurrencyEntry[] conversionNames = new CurrencyEntry[]{
            new CurrencyEntry("ETH", 1, "Ξ"),
            new CurrencyEntry("BTC", 0.07, "฿"),
            new CurrencyEntry("USD", 0, "$")
    };

    private int index = 0;

    public void setIndex(int index) {
        this.index = index;
    }

    public int getIndex() {
        return index;
    }

    public double getRateForChartDisplay() {
        return rateForChartDisplay;
    }

    public CurrencyEntry next() {
        index = (index + 1) % conversionNames.length;
        return conversionNames[index];
    }

    public CurrencyEntry getCurrent() {
        return conversionNames[index];
    }

    public CurrencyEntry previous() {
        index = index > 0 ? index - 1 : conversionNames.length - 1;
        return conversionNames[index];
    }

    public CurrencyEntry getMainCurreny() {
        return conversionNames[2];
    }

    public CurrencyEntry getEtherCurrency() {
        return conversionNames[0];
    }

    public String getCurrencyShort() {
        return conversionNames[index].getShorty();
    }

    public String displayBalanceNicely(double d) {
        if (index == 2)
            return displayUsdNicely(d);
        else
            return displayEthNicely(d);
    }

    public String displayUsdNicely(double d) {
        return formatterUsd.format(d);
    }

    public String displayEthNicely(double d) {
        return formatterCrypt.format(d);
    }

    public String displayEthNicelyExact(double d) {
        return formatterCryptExact.format(d);
    }

    /**
     * Converts given tokenbalance to ETH
     *
     * @param tokenbalance native token balance
     * @param tokenusd     price in USD for each token
     * @return Ether worth of given tokens
     */
    public double convertTokenToEther(double tokenbalance, double tokenusd) {
        return Math.floor((((tokenbalance * tokenusd) / conversionNames[2].getRate()) * 10000)) / 10000;
    }

    public double convertRate(double balance, double rate) {
        if (index == 2) {
            if (balance * rate >= 100000) // dont display cents if bigger than 100k
                return (int) Math.floor(balance * rate);
            return Math.floor(balance * rate * 100) / 100;
        } else {
            if (balance * rate >= 1000)
                return Math.floor(balance * rate * 10) / 10;
            if (balance * rate >= 100)
                return Math.floor(balance * rate * 100) / 100;
            return Math.floor(balance * rate * 1000) / 1000;
        }
    }

    public double weiToEther(long weis) {
        return new BigDecimal(weis).divide(ONE_ETHER, 8, BigDecimal.ROUND_DOWN).doubleValue();
    }

    public String convertRateExact(BigDecimal balance, double rate) {
        if (index == 2) {
            return displayUsdNicely(Math.floor(balance.doubleValue() * rate * 100) / 100) + "";
        } else
            return displayEthNicelyExact(balance.multiply(new BigDecimal(rate)).setScale(7, RoundingMode.CEILING).doubleValue());
    }

    public double convertToUsd(double balance) {
        return Math.floor(balance * getUSDPrice() * 100) / 100;
    }

    /**
     * Used for DetailFragmentOverview "Overall Balance"
     *
     * @param token List of all tokens on an address
     * @return ether price of all tokens combined (exclusive ether balance itself)
     */
    public double sumUpTokenEther(List<TokenDisplay> token) {
        double summedEther = 0;
        for (TokenDisplay t : token) {
            if (t.getShorty().equals("ETH")) continue;
            summedEther += convertTokenToEther(t.getBalanceDouble(), t.getUsdprice());
        }
        return summedEther;
    }

    public double getUSDPrice() {
        return Math.floor(conversionNames[2].getRate() * 100) / 100;
    }

    public double getBTCPrice() {
        return Math.floor(conversionNames[1].getRate() * 10000) / 10000;
    }

    public void updateExchangeRates(final String currency, final NetworkUpdateListener update) throws IOException {
        if (lastUpdateTimestamp + 40 * 60 * 1000 > System.currentTimeMillis() && currency.equals(conversionNames[2].getName())) { // Dont refresh if not older than 40 min and currency hasnt changed
            return;
        }
        if (!currency.equals(conversionNames[2].getName())) {
            conversionNames[2].setName(currency);
            if (currency.equals("USD"))
                conversionNames[2].setShorty("$");
            else if (currency.equals("EUR"))
                conversionNames[2].setShorty("€");
            else if (currency.equals("GPB"))
                conversionNames[2].setShorty("£");
            else if (currency.equals("AUD"))
                conversionNames[2].setShorty("$");
            else if (currency.equals("RUB"))
                conversionNames[2].setShorty("р");
            else if (currency.equals("CHF"))
                conversionNames[2].setShorty("Fr");
            else if (currency.equals("CAD"))
                conversionNames[2].setShorty("$");
            else if (currency.equals("JPY"))
                conversionNames[2].setShorty("¥");

            else
                conversionNames[2].setShorty(currency);
        }

        //Log.d("updateingn", "Initialize price update");
        EtherscanAPI.getInstance().getEtherPrice(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                try {
                    JSONObject data = new JSONObject(response.body().string()).getJSONObject("result");

                    conversionNames[1].setRate(data.getDouble("ethbtc"));
                    conversionNames[2].setRate(data.getDouble("ethusd"));
                    if (!currency.equals("USD"))
                        convert(currency, update);
                    else
                        update.onUpdate(response);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void convert(final String currency, final NetworkUpdateListener update) throws IOException {
        EtherscanAPI.getInstance().getPriceConversionRates(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {

                rateForChartDisplay = ResponseParser.parsePriceConversionRate(currency, response.body().string());
                conversionNames[2].setRate(Math.floor(conversionNames[2].getRate() * rateForChartDisplay * 100) / 100);
                update.onUpdate(response);
            }
        });
    }

} public class RequestCache {

    public static final String TYPE_TOKEN = "TOKEN_";
    public static final String TYPE_TXS_NORMAL = "TXS_NORMAL_";
    public static final String TYPE_TXS_INTERNAL = "TXS_INTERNAL_";
    public static final String TYPE_BALANCES = "BALANCES_";

    private HashMap<String, String> map = new HashMap<String, String>();
    private static RequestCache instance;

    public static RequestCache getInstance() {
        if (instance == null)
            instance = new RequestCache();
        return instance;
    }

    public void put(String type, String address, String response) {
        map.put(type + address, response);
    }

    public String get(String type, String address) {
        return map.get(type + address);
    }

    public boolean contains(String type, String address) {
        return map.containsKey(type + address);
    }

} public class ResponseParser {


    public static ArrayList<TransactionDisplay> parseTransactions(String response, String walletname, String address, byte type) {
        try {
            ArrayList<TransactionDisplay> erg = new ArrayList<TransactionDisplay>();

            JSONArray data = new JSONObject(response).getJSONArray("result");
            for (int i = 0; i < data.length(); i++) {
                String from = data.getJSONObject(i).getString("from");
                String to = data.getJSONObject(i).getString("to");
                String vorzeichen = "+";
                if (address.equalsIgnoreCase(data.getJSONObject(i).getString("from"))) {
                    vorzeichen = "-";
                } else {
                    String temp = from;
                    from = to;
                    to = temp;
                }
                if (data.getJSONObject(i).getString("value").equals("0") && !Settings.showTransactionsWithZero)
                    continue; // Skip contract calls or empty transactions
                erg.add(new TransactionDisplay(
                        from,
                        to,
                        new BigInteger(vorzeichen + data.getJSONObject(i).getString("value")),
                        data.getJSONObject(i).has("confirmations") ? data.getJSONObject(i).getInt("confirmations") : 13,
                        data.getJSONObject(i).getLong("timeStamp") * 1000,
                        walletname,
                        type,
                        data.getJSONObject(i).getString("hash"),
                        data.getJSONObject(i).has("nonce") ? data.getJSONObject(i).getString("nonce") : "0",
                        data.getJSONObject(i).getLong("blockNumber"),
                        data.getJSONObject(i).getInt("gasUsed"),
                        (data.getJSONObject(i).has("gasPrice") ? data.getJSONObject(i).getLong("gasPrice") : 0),
                        (data.getJSONObject(i).has("isError") && data.getJSONObject(i).getInt("isError") == 1)
                ));
            }


            return erg;
        } catch (JSONException e) {
            return new ArrayList<TransactionDisplay>();
        }
    }

    public static ArrayList<WalletDisplay> parseWallets(String response, ArrayList<StorableWallet> storedwallets, Context context) throws Exception {
        ArrayList<WalletDisplay> display = new ArrayList<WalletDisplay>();
        JSONArray data = new JSONObject(response).getJSONArray("result");
        for (int i = 0; i < storedwallets.size(); i++) {
            BigInteger balance = new BigInteger("0");
            for (int j = 0; j < data.length(); j++) {
                if (data.getJSONObject(j).getString("account").equalsIgnoreCase(storedwallets.get(i).getPubKey())) {
                    balance = new BigInteger(data.getJSONObject(i).getString("balance"));
                    break;
                }
            }
            String walletname = AddressNameConverter.getInstance(context).get(storedwallets.get(i).getPubKey());
            display.add(new WalletDisplay(
                    walletname == null ? "New Wallet" : walletname,
                    storedwallets.get(i).getPubKey(),
                    balance,
                    storedwallets.get(i) instanceof WatchWallet ? WalletDisplay.WATCH_ONLY : WalletDisplay.NORMAL
            ));
        }
        return display;
    }

    public static ArrayList<TokenDisplay> parseTokens(Context c, String response, LastIconLoaded callback) throws Exception {
        Log.d("tokentest", response);
        ArrayList<TokenDisplay> display = new ArrayList<TokenDisplay>();
        JSONArray data = new JSONObject(response).getJSONArray("tokens");
        for (int i = 0; i < data.length(); i++) {
            JSONObject currentToken = data.getJSONObject(i);
            try {
                display.add(new TokenDisplay(
                        currentToken.getJSONObject("tokenInfo").getString("name"),
                        currentToken.getJSONObject("tokenInfo").getString("symbol"),
                        new BigDecimal(currentToken.getString("balance")),
                        currentToken.getJSONObject("tokenInfo").getInt("decimals"),
                        currentToken.getJSONObject("tokenInfo").getJSONObject("price").getDouble("rate"),
                        currentToken.getJSONObject("tokenInfo").getString("address"),
                        currentToken.getJSONObject("tokenInfo").getString("totalSupply"),
                        currentToken.getJSONObject("tokenInfo").getLong("holdersCount"),
                        0
                ));
            } catch (JSONException e) {
                e.printStackTrace();
            }

            // Download icon and cache it
            EtherscanAPI.getInstance().loadTokenIcon(c, currentToken.getJSONObject("tokenInfo").getString("name"), i == data.length() - 1, callback);

        }
        return display;
    }

    public static String parseBalance(String response) throws JSONException {
        return parseBalance(response, 7);
    }

    public static String parseBalance(String response, int comma) throws JSONException {
        String balance = new JSONObject(response).getString("result");
        if (balance.equals("0")) return "0";
        return new BigDecimal(balance).divide(new BigDecimal(1000000000000000000d), comma, BigDecimal.ROUND_UP).toPlainString();
    }

    public static BigInteger parseGasPrice(String response) throws Exception {
        String gasprice = new JSONObject(response).getString("result");
        return new BigInteger(gasprice.substring(2), 16);
    }

    // Only call for each address, not the combined one
    /*public static void saveNewestNoncesOfAddresses(Context c, ArrayList<TransactionDisplay> tx, String address){
        try{
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
            long curNonce = -1;
            for(int i=tx.size()-1; i >= 0; i--){
                if(tx.get(i).getFromAddress().equals(address)) { // From address is always our address (thanks to @parseTransactions above for that)
                    curNonce = Long.parseLong(tx.get(tx.size() - 1).getNounce());
                    break;
                }
            }

            long oldNonce = preferences.getLong("NONCE"+address, 0);
            if(curNonce > oldNonce){
                SharedPreferences.Editor editor = preferences.edit();
                editor.putLong("NONCE"+address, curNonce);
                editor.commit();
            }
        }catch(Exception e){
        }
    }*/

    public static double parsePriceConversionRate(String key, String response) {
        try {
            JSONObject jo = new JSONObject(response).getJSONObject("rates");
            return jo.getDouble(key);
        } catch (Exception e) {
            return 1;
        }
    }

} public class TokenAdapter extends RecyclerView.Adapter<TokenAdapter.MyViewHolder> {

    private Context context;
    private List<TokenDisplay> boxlist;
    private int lastPosition = -1;
    private View.OnClickListener listener;
    private View.OnCreateContextMenuListener contextMenuListener;
    private int position;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView name, nativebalance, etherbalance, shorty;
        public TextView image;
        public LinearLayout container;

        public MyViewHolder(View view) {
            super(view);
            nativebalance = (TextView) view.findViewById(R.id.nativebalance);
            name = (TextView) view.findViewById(R.id.tokenname);
            image = (TextView) view.findViewById(R.id.addressimage);
            etherbalance = (TextView) view.findViewById(R.id.etherbalance);
            container = (LinearLayout) view.findViewById(R.id.container);
        }

        public void clearAnimation() {
            container.clearAnimation();
        }
    }


    public TokenAdapter(List<TokenDisplay> boxlist, Context context, View.OnClickListener listener, View.OnCreateContextMenuListener l) {
        this.boxlist = boxlist;
        this.context = context;
        this.listener = listener;
        this.contextMenuListener = l;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.view_w_token, parent, false);

        itemView.setOnClickListener(listener);
        itemView.setOnCreateContextMenuListener(contextMenuListener);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        TokenDisplay box = boxlist.get(position);

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                setPosition(position);
                return false;
            }
        });

        holder.name.setText(box.getName());
        double tbalance = box.getBalanceDouble();
        holder.nativebalance.setText(ExchangeCalculator.getInstance().displayEthNicely(tbalance) + " " + box.getShorty());
        holder.etherbalance.setText(
                ExchangeCalculator.getInstance().displayEthNicely(
                        ExchangeCalculator.getInstance().convertRate(
                                ExchangeCalculator.getInstance().convertTokenToEther(tbalance, box.getUsdprice()),
                                ExchangeCalculator.getInstance().getCurrent().getRate()
                        )) + " " + ExchangeCalculator.getInstance().getCurrent().getShorty());
        if (box.getContractAddr() != null && box.getContractAddr().length() > 3) {
            holder.image.setText("");
            String iconName = box.getName();
            if (iconName.indexOf(" ") > 0)
                iconName = iconName.substring(0, iconName.indexOf(" "));
            holder.image.setBackground(new BitmapDrawable(context.getResources(), TokenIconCache.getInstance(context).get(iconName)));
        } else {
            holder.image.setText("Ξ");
            holder.image.setBackgroundResource(0);
            holder.etherbalance.setText(
                    ExchangeCalculator.getInstance().displayEthNicely(
                            ExchangeCalculator.getInstance().convertRate(tbalance, ExchangeCalculator.getInstance().getCurrent().getRate())) + " " +
                            ExchangeCalculator.getInstance().getCurrent().getShorty());
        }

        setAnimation(holder.container, position);
    }


    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

    @Override
    public void onViewRecycled(TokenAdapter.MyViewHolder holder) {
        holder.itemView.setOnLongClickListener(null);
        super.onViewRecycled(holder);
    }

    private void setAnimation(View viewToAnimate, int position) {
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(context, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_bottom);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

    @Override
    public void onViewDetachedFromWindow(MyViewHolder holder) {
        holder.clearAnimation();
    }


    @Override
    public int getItemCount() {
        return boxlist.size();
    }
} public class WalletStorage {

    private ArrayList<StorableWallet> mapdb;
    private static WalletStorage instance;
    private String walletToExport; // Used as temp if users wants to export but still needs to grant write permission

    public static WalletStorage getInstance(Context context) {
        if (instance == null)
            instance = new WalletStorage(context);
        return instance;
    }

    private WalletStorage(Context context) {
        try {
            load(context);
        } catch (Exception e) {
            e.printStackTrace();
            mapdb = new ArrayList<StorableWallet>();
        }
        if (mapdb.size() == 0) // Try to find local wallets
            checkForWallets(context);
    }

    public synchronized boolean add(StorableWallet addresse, Context context) {
        for (int i = 0; i < mapdb.size(); i++)
            if (mapdb.get(i).getPubKey().equalsIgnoreCase(addresse.getPubKey())) return false;
        mapdb.add(addresse);
        save(context);
        return true;
    }

    public synchronized ArrayList<StorableWallet> get() {
        return mapdb;
    }

    public synchronized ArrayList<String> getFullOnly() {
        ArrayList<String> erg = new ArrayList<String>();
        if (mapdb.size() == 0) return erg;
        for (int i = 0; i < mapdb.size(); i++) {
            StorableWallet cur = mapdb.get(i);
            if (cur instanceof FullWallet)
                erg.add(cur.getPubKey());
        }
        return erg;
    }

    public synchronized boolean isFullWallet(String addr) {
        if (mapdb.size() == 0) return false;
        for (int i = 0; i < mapdb.size(); i++) {
            StorableWallet cur = mapdb.get(i);
            if (cur instanceof FullWallet && cur.getPubKey().equalsIgnoreCase(addr))
                return true;
        }
        return false;
    }

    public void removeWallet(String address, Context context) {
        int position = -1;
        for (int i = 0; i < mapdb.size(); i++) {
            if (mapdb.get(i).getPubKey().equalsIgnoreCase(address)) {
                position = i;
                break;
            }
        }
        if (position >= 0) {
            if (mapdb.get(position) instanceof FullWallet) // IF full wallet delete private key too
                new File(context.getFilesDir(), address.substring(2, address.length())).delete();
            mapdb.remove(position);
        }
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
        editor.remove(address);
        editor.apply();
        save(context);
    }

    public void checkForWallets(Context c) {
        // Full wallets
        File[] wallets = c.getFilesDir().listFiles();
        if (wallets == null) {
            return;
        }
        for (int i = 0; i < wallets.length; i++) {
            if (wallets[i].isFile()) {
                if (wallets[i].getName().length() == 40) {
                    add(new FullWallet("0x" + wallets[i].getName(), wallets[i].getName()), c);
                }
            }
        }

        // Watch only
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
        Map<String, ?> allEntries = preferences.getAll();
        for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
            if (entry.getKey().length() == 42 && !mapdb.contains(entry.getKey()))
                add(new WatchWallet(entry.getKey()), c);
        }
        if (mapdb.size() > 0)
            save(c);
    }

    public void importingWalletsDetector(MainActivity c) {
        if (!ExternalStorageHandler.hasReadPermission(c)) {
            ExternalStorageHandler.askForPermissionRead(c);
            return;
        }
        File[] wallets = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Lunary/").listFiles();
        if (wallets == null) {
            Dialogs.noImportWalletsFound(c);
            return;
        }
        ArrayList<File> foundImports = new ArrayList<File>();
        for (int i = 0; i < wallets.length; i++) {
            if (wallets[i].isFile()) {
                if (wallets[i].getName().startsWith("UTC") && wallets[i].getName().length() >= 40) {
                    foundImports.add(wallets[i]); // Mist naming
                } else if (wallets[i].getName().length() >= 40) {
                    int position = wallets[i].getName().indexOf(".json");
                    if (position < 0) continue;
                    String addr = wallets[i].getName().substring(0, position);
                    if (addr.length() == 40 && !mapdb.contains("0x" + wallets[i].getName())) {
                        foundImports.add(wallets[i]); // Exported with Lunary
                    }
                }
            }
        }
        if (foundImports.size() == 0) {
            Dialogs.noImportWalletsFound(c);
            return;
        }
        Dialogs.importWallets(c, foundImports);
    }

    public void setWalletForExport(String wallet) {
        walletToExport = wallet;
    }

    public boolean exportWallet(Activity c) {
        return exportWallet(c, false);
    }

    public void importWallets(Context c, ArrayList<File> toImport) throws Exception {
        for (int i = 0; i < toImport.size(); i++) {

            String address = stripWalletName(toImport.get(i).getName());
            if (address.length() == 40) {
                copyFile(toImport.get(i), new File(c.getFilesDir(), address));
                if(! BuildConfig.DEBUG)
                    toImport.get(i).delete();
                WalletStorage.getInstance(c).add(new FullWallet("0x" + address, address), c);
                AddressNameConverter.getInstance(c).put("0x" + address, "Wallet " + ("0x" + address).substring(0, 6), c);

                Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                Uri fileContentUri = Uri.fromFile(toImport.get(i)); // With 'permFile' being the File object
                mediaScannerIntent.setData(fileContentUri);
                c.sendBroadcast(mediaScannerIntent); // With 'this' being the context, e.g. the activity

            }
        }
    }

    public static String stripWalletName(String s) {
        if (s.lastIndexOf("--") > 0)
            s = s.substring(s.lastIndexOf("--") + 2);
        if (s.endsWith(".json"))
            s = s.substring(0, s.indexOf(".json"));
        return s;
    }

    private boolean exportWallet(Activity c, boolean already) {
        if (walletToExport == null) return false;
        if (walletToExport.startsWith("0x"))
            walletToExport = walletToExport.substring(2);

        if (ExternalStorageHandler.hasPermission(c)) {
            File folder = new File(Environment.getExternalStorageDirectory(), "Lunary");
            if (!folder.exists()) folder.mkdirs();

            File storeFile = new File(folder, walletToExport + ".json");
            try {
                copyFile(new File(c.getFilesDir(), walletToExport), storeFile);
            } catch (IOException e) {
                return false;
            }

            // fix, otherwise won't show up via USB
            Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri fileContentUri = Uri.fromFile(storeFile); // With 'permFile' being the File object
            mediaScannerIntent.setData(fileContentUri);
            c.sendBroadcast(mediaScannerIntent); // With 'this' being the context, e.g. the activity
            return true;
        } else if (!already) {
            ExternalStorageHandler.askForPermission(c);
            return exportWallet(c, true);
        } else {
            return false;
        }
    }


    private void copyFile(File src, File dst) throws IOException {
        FileChannel inChannel = new FileInputStream(src).getChannel();
        FileChannel outChannel = new FileOutputStream(dst).getChannel();
        try {
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally {
            if (inChannel != null)
                inChannel.close();
            if (outChannel != null)
                outChannel.close();
        }
    }

    public Credentials getFullWallet(Context context, String password, String wallet) throws IOException, JSONException, CipherException {
        if (wallet.startsWith("0x"))
            wallet = wallet.substring(2, wallet.length());
        return WalletUtils.loadCredentials(password, new File(context.getFilesDir(), wallet));
    }


    public synchronized void save(Context context) {
        FileOutputStream fout;
        try {
            fout = new FileOutputStream(new File(context.getFilesDir(), "wallets.dat"));
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject(mapdb);
            oos.close();
            fout.close();
        } catch (Exception e) {
        }
    }

    @SuppressWarnings("unchecked")
    public synchronized void load(Context context) throws IOException, ClassNotFoundException {
        FileInputStream fout = new FileInputStream(new File(context.getFilesDir(), "wallets.dat"));
        ObjectInputStream oos = new ObjectInputStream(new BufferedInputStream(fout));
        mapdb = (ArrayList<StorableWallet>) oos.readObject();
        oos.close();
        fout.close();
    }

}
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import com.google.android.material.appbar.AppBarLayout;
import androidx.fragment.app.Fragment;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.github.clans.fab.FloatingActionButton;
import com.github.clans.fab.FloatingActionMenu;
import org.json.JSONException;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import rehanced.com.simpleetherwallet.R;
import rehanced.com.simpleetherwallet.activities.AddressDetailActivity;
import rehanced.com.simpleetherwallet.activities.SendActivity;
import rehanced.com.simpleetherwallet.data.CurrencyEntry;
import rehanced.com.simpleetherwallet.data.TokenDisplay;
import rehanced.com.simpleetherwallet.data.WatchWallet;
import rehanced.com.simpleetherwallet.interfaces.LastIconLoaded;
import rehanced.com.simpleetherwallet.network.EtherscanAPI;
import rehanced.com.simpleetherwallet.utils.AddressNameConverter;
import rehanced.com.simpleetherwallet.utils.AppBarStateChangeListener;
import rehanced.com.simpleetherwallet.utils.Blockies;
import rehanced.com.simpleetherwallet.utils.Dialogs;
import rehanced.com.simpleetherwallet.utils.ExchangeCalculator;
import rehanced.com.simpleetherwallet.utils.RequestCache;
import rehanced.com.simpleetherwallet.utils.ResponseParser;
import rehanced.com.simpleetherwallet.utils.TokenAdapter;
import rehanced.com.simpleetherwallet.utils.WalletStorage;
package rehanced.com.simpleetherwallet.fragments;






public class FragmentDetailOverview extends Fragment implements View.OnClickListener, View.OnCreateContextMenuListener, LastIconLoaded {

    private AddressDetailActivity ac;
    private String ethaddress = "";
    private byte type;
    private TextView balance, address, currency;
    private ImageView icon;
    private LinearLayout header;
    BigDecimal balanceDouble = new BigDecimal("0");
    private FloatingActionMenu fabmenu;
    private RecyclerView recyclerView;
    private TokenAdapter walletAdapter;
    private List<TokenDisplay> token = new ArrayList<>();
    private SwipeRefreshLayout swipeLayout;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_detail_ov, container, false);

        ac = (AddressDetailActivity) this.getActivity();
        ethaddress = getArguments().getString("ADDRESS");
        type = getArguments().getByte("TYPE");

        icon = (ImageView) rootView.findViewById(R.id.addressimage);
        address = (TextView) rootView.findViewById(R.id.ethaddress);
        balance = (TextView) rootView.findViewById(R.id.balance);
        currency = (TextView) rootView.findViewById(R.id.currency);
        header = (LinearLayout) rootView.findViewById(R.id.header);
        fabmenu = (FloatingActionMenu) rootView.findViewById(R.id.fabmenu);

        CurrencyEntry cur = ExchangeCalculator.getInstance().getCurrent();
        balanceDouble = new BigDecimal(getArguments().getDouble("BALANCE"));
        balance.setText(ExchangeCalculator.getInstance().convertRateExact(balanceDouble, cur.getRate()) + "");
        currency.setText(cur.getName());

        recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
        walletAdapter = new TokenAdapter(token, ac, this, this);
        LinearLayoutManager mgr = new LinearLayoutManager(ac.getApplicationContext());
        RecyclerView.LayoutManager mLayoutManager = mgr;
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(walletAdapter);
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), mgr.getOrientation());
        recyclerView.addItemDecoration(dividerItemDecoration);

        swipeLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipeRefreshLayout2);
        swipeLayout.setColorSchemeColors(ac.getResources().getColor(R.color.colorPrimary));
        swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                try {
                    update(true);
                } catch (IOException e) {
                    if (ac != null)
                        ac.snackError("Connection problem");
                    e.printStackTrace();
                }
            }
        });

        header.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                CurrencyEntry cur = ExchangeCalculator.getInstance().next();
                balance.setText(ExchangeCalculator.getInstance().convertRateExact(balanceDouble, cur.getRate()) + "");
                currency.setText(cur.getName());
                walletAdapter.notifyDataSetChanged();
                if (ac != null)
                    ac.broadCastDataSetChanged();
            }
        });

        icon.setImageBitmap(Blockies.createIcon(ethaddress, 24));
        address.setText(ethaddress);

        FloatingActionButton fab_setName = (FloatingActionButton) rootView.findViewById(R.id.set_name);
        fab_setName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                setName();
            }
        });

        FloatingActionButton send_ether = (FloatingActionButton) rootView.findViewById(R.id.send_ether); // Send Ether to
        send_ether.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (WalletStorage.getInstance(ac).getFullOnly().size() == 0) {
                    Dialogs.noFullWallet(ac);