<commit_before>package com.samourai.wallet.home;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.transition.ChangeBounds;
import android.support.transition.TransitionManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.dm.zbar.android.scanner.ZBarConstants;
import com.samourai.wallet.ExodusActivity;
import com.samourai.wallet.JSONRPC.JSONRPC;
import com.samourai.wallet.JSONRPC.PoW;
import com.samourai.wallet.JSONRPC.TrustedNodeUtil;
import com.samourai.wallet.R;
import com.samourai.wallet.ReceiveActivity;
import com.samourai.wallet.SamouraiWallet;
import com.samourai.wallet.SettingsActivity;
import com.samourai.wallet.access.AccessFactory;
import com.samourai.wallet.api.APIFactory;
import com.samourai.wallet.api.Tx;
import com.samourai.wallet.bip47.BIP47Meta;
import com.samourai.wallet.bip47.BIP47Util;
import com.samourai.wallet.cahoots.Cahoots;
import com.samourai.wallet.cahoots.CahootsUtil;
import com.samourai.wallet.crypto.AESUtil;
import com.samourai.wallet.crypto.DecryptionException;
import com.samourai.wallet.fragments.CameraFragmentBottomSheet;
import com.samourai.wallet.hd.HD_Wallet;
import com.samourai.wallet.hd.HD_WalletFactory;
import com.samourai.wallet.home.adapters.TxAdapter;
import com.samourai.wallet.network.NetworkDashboard;
import com.samourai.wallet.network.dojo.DojoUtil;
import com.samourai.wallet.payload.PayloadUtil;
import com.samourai.wallet.paynym.ClaimPayNymActivity;
import com.samourai.wallet.paynym.PayNymHome;
import com.samourai.wallet.permissions.PermissionsUtil;
import com.samourai.wallet.ricochet.RicochetMeta;
import com.samourai.wallet.segwit.bech32.Bech32Util;
import com.samourai.wallet.send.BlockedUTXO;
import com.samourai.wallet.send.MyTransactionOutPoint;
import com.samourai.wallet.send.SendActivity;
import com.samourai.wallet.send.SweepUtil;
import com.samourai.wallet.send.UTXO;
import com.samourai.wallet.send.cahoots.ManualCahootsActivity;
import com.samourai.wallet.service.JobRefreshService;
import com.samourai.wallet.service.WebSocketService;
import com.samourai.wallet.tor.TorManager;
import com.samourai.wallet.tor.TorService;
import com.samourai.wallet.tx.TxDetailsActivity;
import com.samourai.wallet.util.AppUtil;
import com.samourai.wallet.util.CharSequenceX;
import com.samourai.wallet.util.FormatsUtil;
import com.samourai.wallet.util.LogUtil;
import com.samourai.wallet.util.MessageSignUtil;
import com.samourai.wallet.util.MonetaryUtil;
import com.samourai.wallet.util.PrefsUtil;
import com.samourai.wallet.util.PrivKeyReader;
import com.samourai.wallet.util.TimeOutUtil;
import com.samourai.wallet.utxos.UTXOSActivity;
import com.samourai.wallet.whirlpool.WhirlpoolMain;
import com.samourai.wallet.whirlpool.WhirlpoolMeta;
import com.samourai.wallet.widgets.ItemDividerDecorator;
import com.samourai.whirlpool.client.wallet.AndroidWhirlpoolWalletService;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.crypto.BIP38PrivateKey;
import org.bitcoinj.crypto.MnemonicException;
import org.bitcoinj.script.Script;
import org.bouncycastle.util.encoders.Hex;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class BalanceActivity extends AppCompatActivity {

    private final static int SCAN_COLD_STORAGE = 2011;
    private final static int SCAN_QR = 2012;
    private static final String TAG = "BalanceActivity";


    private List<Tx> txs = null;
    private RecyclerView TxRecyclerView;
    private ProgressBar progressBar;
    private BalanceViewModel balanceViewModel;
    private int account = 0;

    private PoWTask powTask = null;
    private RicochetQueueTask ricochetQueueTask = null;
    private com.github.clans.fab.FloatingActionMenu menuFab;
    private SwipeRefreshLayout txSwipeLayout;
    private CollapsingToolbarLayout mCollapsingToolbar;
    private CompositeDisposable compositeDisposable = new CompositeDisposable();
    private Toolbar toolbar;
    private Menu menu;
    private ImageView menuTorIcon;
    private ProgressBar progressBarMenu;
    private View whirlpoolFab,sendFab,receiveFab,paynymFab;

    public static final String ACTION_INTENT = "com.samourai.wallet.BalanceFragment.REFRESH";
    protected BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, Intent intent) {

            if (ACTION_INTENT.equals(intent.getAction())) {
                if (progressBar != null) {
                    progressBar.setVisibility(View.VISIBLE);
                }
                final boolean notifTx = intent.getBooleanExtra("notifTx", false);
                final boolean fetch = intent.getBooleanExtra("fetch", false);

                final String rbfHash;
                final String blkHash;
                if (intent.hasExtra("rbf")) {
                    rbfHash = intent.getStringExtra("rbf");
                } else {
                    rbfHash = null;
                }
                if (intent.hasExtra("hash")) {
                    blkHash = intent.getStringExtra("hash");
                } else {
                    blkHash = null;
                }

                Handler handler = new Handler();
                handler.post(() -> {
                    refreshTx(notifTx, false, false);

                    if (BalanceActivity.this != null) {

                        if (rbfHash != null) {
                            new AlertDialog.Builder(BalanceActivity.this)
                                    .setTitle(R.string.app_name)
                                    .setMessage(rbfHash + "\n\n" + getString(R.string.rbf_incoming))
                                    .setCancelable(true)
                                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {

                                            doExplorerView(rbfHash);

                                        }
                                    })
                                    .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {
                                            ;
                                        }
                                    }).show();

                        }

                    }
                });

                if (BalanceActivity.this != null && blkHash != null && PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.USE_TRUSTED_NODE, false) == true && TrustedNodeUtil.getInstance().isSet()) {

//                    BalanceActivity.this.runOnUiThread(new Runnable() {
//                    @Override
                    handler.post(new Runnable() {
                        public void run() {
                            if (powTask == null || powTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
                                powTask = new PoWTask();
                                powTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, blkHash);
                            }
                        }

                    });

                }

            }

        }
    };

    public static final String DISPLAY_INTENT = "com.samourai.wallet.BalanceFragment.DISPLAY";
    protected BroadcastReceiver receiverDisplay = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, Intent intent) {

            if (DISPLAY_INTENT.equals(intent.getAction())) {

                updateDisplay(true);

                List<UTXO> utxos = APIFactory.getInstance(BalanceActivity.this).getUtxos(false);
                for (UTXO utxo : utxos) {
                    List<MyTransactionOutPoint> outpoints = utxo.getOutpoints();
                    for (MyTransactionOutPoint out : outpoints) {

                        byte[] scriptBytes = out.getScriptBytes();
                        String address = null;
                        try {
                            if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
                                address = Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes));
                            } else {
                                address = new Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                            }
                        } catch (Exception e) {
                        }
                        String path = APIFactory.getInstance(BalanceActivity.this).getUnspentPaths().get(address);
                        if (path != null && path.startsWith("M/1/")) {
                            continue;
                        }

                        final String hash = out.getHash().toString();
                        final int idx = out.getTxOutputN();
                        final long amount = out.getValue().longValue();

                        if (amount < BlockedUTXO.BLOCKED_UTXO_THRESHOLD &&
                                !BlockedUTXO.getInstance().contains(hash, idx) &&
                                !BlockedUTXO.getInstance().containsNotDusted(hash, idx)) {

//                            BalanceActivity.this.runOnUiThread(new Runnable() {
//                            @Override
                            Handler handler = new Handler();
                            handler.post(new Runnable() {
                                public void run() {

                                    String message = BalanceActivity.this.getString(R.string.dusting_attempt);
                                    message += "\n\n";
                                    message += BalanceActivity.this.getString(R.string.dusting_attempt_amount);
                                    message += " ";
                                    message += Coin.valueOf(amount).toPlainString();
                                    message += " BTC\n";
                                    message += BalanceActivity.this.getString(R.string.dusting_attempt_id);
                                    message += " ";
                                    message += hash + "-" + idx;

                                    AlertDialog.Builder dlg = new AlertDialog.Builder(BalanceActivity.this)
                                            .setTitle(R.string.dusting_tx)
                                            .setMessage(message)
                                            .setCancelable(false)
                                            .setPositiveButton(R.string.dusting_attempt_mark_unspendable, new DialogInterface.OnClickListener() {
                                                public void onClick(DialogInterface dialog, int whichButton) {

                                                    BlockedUTXO.getInstance().add(hash, idx, amount);

                                                }
                                            }).setNegativeButton(R.string.dusting_attempt_ignore, new DialogInterface.OnClickListener() {
                                                public void onClick(DialogInterface dialog, int whichButton) {

                                                    BlockedUTXO.getInstance().addNotDusted(hash, idx);

                                                }
                                            });
                                    if (!isFinishing()) {
                                        dlg.show();
                                    }

                                }
                            });

                        }

                    }

                }

            }

        }
    };

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_balance);
        balanceViewModel = ViewModelProviders.of(this).get(BalanceViewModel.class);
        makePaynymAvatarcache();
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        if ((getIntent().getExtras() != null && getIntent().getExtras().containsKey("_account"))) {
            account = getIntent().getExtras().getInt("_account");
        }

        TxRecyclerView = findViewById(R.id.rv_txes);
        progressBar = findViewById(R.id.progressBar);
        toolbar = findViewById(R.id.toolbar);
        mCollapsingToolbar = findViewById(R.id.toolbar_layout);
        txSwipeLayout = findViewById(R.id.tx_swipe_container);

        setSupportActionBar(toolbar);
        TxRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        Drawable drawable = this.getResources().getDrawable(R.drawable.divider);
        TxRecyclerView.addItemDecoration(new ItemDividerDecorator(drawable));
        menuFab = findViewById(R.id.fab_menu);
        txs = new ArrayList<>();
        whirlpoolFab = findViewById(R.id.whirlpool_fab);
        sendFab =  findViewById(R.id.send_fab);
        receiveFab =  findViewById(R.id.receive_fab);
        paynymFab =  findViewById(R.id.paynym_fab);

        findViewById(R.id.whirlpool_fab).setOnClickListener(view -> {
            Intent intent = new Intent(BalanceActivity.this, WhirlpoolMain.class);
            startActivity(intent);
            menuFab.toggle(true);
        });

        sendFab.setOnClickListener(view -> {
            Intent intent = new Intent(BalanceActivity.this, SendActivity.class);
            intent.putExtra("via_menu", true);
            intent.putExtra("_account", account);
            startActivity(intent);
            menuFab.toggle(true);
        });
        setBalance(0L, false);
        receiveFab.setOnClickListener(view -> {
            menuFab.toggle(true);

            try {
                HD_Wallet hdw = HD_WalletFactory.getInstance(BalanceActivity.this).get();

                if (hdw != null) {
                    Intent intent = new Intent(BalanceActivity.this, ReceiveActivity.class);
                    startActivity(intent);
                }


            } catch (IOException | MnemonicException.MnemonicLengthException e) {
            }
        });
        paynymFab.setOnClickListener(view -> {
            menuFab.toggle(true);
            Intent intent = new Intent(BalanceActivity.this, PayNymHome.class);
            startActivity(intent);
        });
        txSwipeLayout.setOnRefreshListener(() -> {
            refreshTx(false, true, false);
            txSwipeLayout.setRefreshing(false);
            progressBar.setVisibility(View.VISIBLE);
        });

        IntentFilter filter = new IntentFilter(ACTION_INTENT);
        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiver, filter);
        IntentFilter filterDisplay = new IntentFilter(DISPLAY_INTENT);
        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiverDisplay, filterDisplay);

        if (!PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || !PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtil.getInstance(BalanceActivity.this).showRequestPermissionsInfoAlertDialog(PermissionsUtil.READ_WRITE_EXTERNAL_PERMISSION_CODE);
        }
        if (!PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.CAMERA)) {
            PermissionsUtil.getInstance(BalanceActivity.this).showRequestPermissionsInfoAlertDialog(PermissionsUtil.CAMERA_PERMISSION_CODE);
        }

        if (PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_CLAIMED, false) == true && PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, false) == false) {
            doFeaturePayNymUpdate();
        } else if (PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_CLAIMED, false) == false &&
                PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_REFUSED, false) == false) {
            doClaimPayNym();
        } else {
        }

        if (RicochetMeta.getInstance(BalanceActivity.this).getQueue().size() > 0) {
            if (ricochetQueueTask == null || ricochetQueueTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
                ricochetQueueTask = new RicochetQueueTask();
                ricochetQueueTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
            }
        }

        if (!AppUtil.getInstance(BalanceActivity.this).isClipboardSeen()) {
            doClipboardCheck();
        }


        if (!AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            startService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }
        setUpTor();
        initViewModel();
        progressBar.setVisibility(View.VISIBLE);

        if (account == 0) {
            final Handler delayedHandler = new Handler();
            delayedHandler.postDelayed(() -> {

                boolean notifTx = false;
                Bundle extras = getIntent().getExtras();
                if (extras != null && extras.containsKey("notifTx")) {
                    notifTx = extras.getBoolean("notifTx");
                }

                refreshTx(notifTx, false, true);

                updateDisplay(false);
            }, 100L);
            getSupportActionBar().setIcon(R.drawable.ic_samourai_logo_toolbar);
            balanceViewModel.loadOfflineData();
        } else {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            receiveFab.setVisibility(View.GONE);
            whirlpoolFab.setVisibility(View.GONE);
            paynymFab.setVisibility(View.GONE);
            new Handler().postDelayed(() -> updateDisplay(true), 600L);

        }
        updateDisplay(false);
        checkDeepLinks();
    }

    private void checkDeepLinks() {
        Bundle bundle = getIntent().getExtras();
        if (bundle == null) {
            return;
        }
        if (bundle.containsKey("pcode") || bundle.containsKey("uri") || bundle.containsKey("amount")) {
            if (balanceViewModel.getBalance().getValue() != null)
                bundle.putLong("balance", balanceViewModel.getBalance().getValue());
            Intent intent = new Intent(this, SendActivity.class);
            intent.putExtra("_account",account);
            intent.putExtras(bundle);
            startActivity(intent);
        }

    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    private void initViewModel() {
        TxAdapter adapter = new TxAdapter(getApplicationContext(), new ArrayList<>());
        adapter.setHasStableIds(true);
        adapter.setClickListener((position, tx) -> txDetails(tx));

        TxRecyclerView.setAdapter(adapter);

        balanceViewModel.getBalance().observe(this, balance -> {
            if (balance < 0) {
                return;
            }
            if (balanceViewModel.getSatState().getValue() != null) {
                setBalance(balance, balanceViewModel.getSatState().getValue());
            } else {
                setBalance(balance, false);
            }
        });
        adapter.setTxes(balanceViewModel.getTxs().getValue());
        setBalance(balanceViewModel.getBalance().getValue(), false);

        balanceViewModel.getSatState().observe(this, state -> {
            if (state == null) {
                state = false;
            }
            setBalance(balanceViewModel.getBalance().getValue(), state);
            adapter.toggleDisplayUnit(state);
        });
        balanceViewModel.getTxs().observe(this, new Observer<List<Tx>>() {
            @Override
            public void onChanged(@Nullable List<Tx> list) {
                adapter.setTxes(list);
            }
        });
        mCollapsingToolbar.setOnClickListener(view -> balanceViewModel.toggleSat());

    }

    private void setBalance(Long balance, boolean isSat) {
        if (balance == null) {
            return;
        }

        if (getSupportActionBar() != null) {
            TransitionManager.beginDelayedTransition(mCollapsingToolbar, new ChangeBounds());

            String displayAmount = "".concat(isSat ? getSatoshiDisplayAmount(balance) : getBTCDisplayAmount(balance));
            String Unit = isSat ? getSatoshiDisplayUnits() : getBTCDisplayUnits();

            displayAmount = displayAmount.concat(" ").concat(Unit);
            toolbar.setTitle(displayAmount);
            setTitle(displayAmount);
            mCollapsingToolbar.setTitle(displayAmount);

        }


        Log.i(TAG, "setBalance: ".concat(getBTCDisplayAmount(balance)));

    }

    @Override
    public void onResume() {
        super.onResume();

//        IntentFilter filter = new IntentFilter(ACTION_INTENT);
//        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiver, filter);

        AppUtil.getInstance(BalanceActivity.this).checkTimeOut();

        Intent intent = new Intent("com.samourai.wallet.MainActivity2.RESTART_SERVICE");
        LocalBroadcastManager.getInstance(BalanceActivity.this).sendBroadcast(intent);

    }

    public View createTag(String text){
        float scale = getResources().getDisplayMetrics().density;
        LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        TextView textView = new TextView(getApplicationContext());
        textView.setText(text);
        textView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
        textView.setLayoutParams(lparams);
        textView.setBackgroundResource(R.drawable.tag_round_shape);
        textView.setPadding((int) (8 * scale + 0.5f), (int) (6 * scale + 0.5f), (int) (8 * scale + 0.5f), (int) (6 * scale + 0.5f));
        textView.setTypeface(Typeface.DEFAULT_BOLD);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11);
        return textView;
    }

    @Override
    public void onPause() {
        super.onPause();

//        ibQuickSend.collapse();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            stopService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }

    }


    private void makePaynymAvatarcache() {
        try {

            ArrayList<String> paymentCodes = new ArrayList<>(BIP47Meta.getInstance().getSortedByLabels(false, true));
            for (String code : paymentCodes) {
                Picasso.with(getBaseContext())
                        .load(com.samourai.wallet.bip47.paynym.WebUtil.PAYNYM_API + code + "/avatar").fetch(new Callback() {
                    @Override
                    public void onSuccess() {
                        /*NO OP*/
                    }

                    @Override
                    public void onError() {
                        /*NO OP*/
                    }
                });
            }

        } catch (Exception ignored) {

        }
    }

    @Override
    public void onDestroy() {

        LocalBroadcastManager.getInstance(BalanceActivity.this).unregisterReceiver(receiver);
        LocalBroadcastManager.getInstance(BalanceActivity.this).unregisterReceiver(receiverDisplay);

        if (AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            stopService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }

        if(isFinishing()){
            // disconnect Whirlpool on app exit
            AndroidWhirlpoolWalletService.getInstance().closeWallet();
        }

        super.onDestroy();

        if(compositeDisposable != null && !compositeDisposable.isDisposed()) {
            compositeDisposable.dispose();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);

        menu.findItem(R.id.action_refresh).setVisible(false);
        menu.findItem(R.id.action_share_receive).setVisible(false);
        menu.findItem(R.id.action_ricochet).setVisible(false);
        menu.findItem(R.id.action_empty_ricochet).setVisible(false);
        menu.findItem(R.id.action_sign).setVisible(false);
        menu.findItem(R.id.action_fees).setVisible(false);
        menu.findItem(R.id.action_batch).setVisible(false);

        WhirlpoolMeta.getInstance(getApplicationContext());
        if (account == WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix()) {
            menu.findItem(R.id.action_network_dashboard).setVisible(false);
            MenuItem item = menu.findItem(R.id.action_menu_account);
            item.setActionView(createTag(" POST-MIX "));
            item.setVisible(true);
            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

        }
        this.menu = menu;

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        // noinspection SimplifiableIfStatement
        if (id == R.id.action_network_dashboard) {
            startActivity(new Intent(this, NetworkDashboard.class));
        }    // noinspection SimplifiableIfStatement
        if (id == R.id.action_copy_cahoots) {
            ClipboardManager clipboard = (ClipboardManager)  getSystemService(Context.CLIPBOARD_SERVICE);
            if(clipboard.hasPrimaryClip())    {
                ClipData.Item clipItem = clipboard.getPrimaryClip().getItemAt(0);

                if(Cahoots.isCahoots(clipItem.getText().toString().trim())){
                    Intent cahootIntent = new Intent(this, ManualCahootsActivity.class);
                    cahootIntent.putExtra("payload",clipItem.getText().toString().trim());
                    startActivity(cahootIntent);
                }else {
                    Toast.makeText(this,R.string.cannot_process_cahoots,Toast.LENGTH_SHORT).show();
                }
            }
            else    {
                Toast.makeText(this,R.string.clipboard_empty,Toast.LENGTH_SHORT).show();
            }
        }
        if (id == R.id.action_settings) {
            doSettings();
        } else if (id == R.id.action_support) {
            doSupport();
        } else if (id == R.id.action_sweep) {
            if (!AppUtil.getInstance(BalanceActivity.this).isOfflineMode()) {<commit_msg>close balance activity when back button pressed <commit_after>package com.samourai.wallet.home;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.transition.ChangeBounds;
import android.support.transition.TransitionManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.dm.zbar.android.scanner.ZBarConstants;
import com.samourai.wallet.ExodusActivity;
import com.samourai.wallet.JSONRPC.JSONRPC;
import com.samourai.wallet.JSONRPC.PoW;
import com.samourai.wallet.JSONRPC.TrustedNodeUtil;
import com.samourai.wallet.R;
import com.samourai.wallet.ReceiveActivity;
import com.samourai.wallet.SamouraiWallet;
import com.samourai.wallet.SettingsActivity;
import com.samourai.wallet.access.AccessFactory;
import com.samourai.wallet.api.APIFactory;
import com.samourai.wallet.api.Tx;
import com.samourai.wallet.bip47.BIP47Meta;
import com.samourai.wallet.bip47.BIP47Util;
import com.samourai.wallet.cahoots.Cahoots;
import com.samourai.wallet.cahoots.CahootsUtil;
import com.samourai.wallet.crypto.AESUtil;
import com.samourai.wallet.crypto.DecryptionException;
import com.samourai.wallet.fragments.CameraFragmentBottomSheet;
import com.samourai.wallet.hd.HD_Wallet;
import com.samourai.wallet.hd.HD_WalletFactory;
import com.samourai.wallet.home.adapters.TxAdapter;
import com.samourai.wallet.network.NetworkDashboard;
import com.samourai.wallet.network.dojo.DojoUtil;
import com.samourai.wallet.payload.PayloadUtil;
import com.samourai.wallet.paynym.ClaimPayNymActivity;
import com.samourai.wallet.paynym.PayNymHome;
import com.samourai.wallet.permissions.PermissionsUtil;
import com.samourai.wallet.ricochet.RicochetMeta;
import com.samourai.wallet.segwit.bech32.Bech32Util;
import com.samourai.wallet.send.BlockedUTXO;
import com.samourai.wallet.send.MyTransactionOutPoint;
import com.samourai.wallet.send.SendActivity;
import com.samourai.wallet.send.SweepUtil;
import com.samourai.wallet.send.UTXO;
import com.samourai.wallet.send.cahoots.ManualCahootsActivity;
import com.samourai.wallet.service.JobRefreshService;
import com.samourai.wallet.service.WebSocketService;
import com.samourai.wallet.tor.TorManager;
import com.samourai.wallet.tor.TorService;
import com.samourai.wallet.tx.TxDetailsActivity;
import com.samourai.wallet.util.AppUtil;
import com.samourai.wallet.util.CharSequenceX;
import com.samourai.wallet.util.FormatsUtil;
import com.samourai.wallet.util.LogUtil;
import com.samourai.wallet.util.MessageSignUtil;
import com.samourai.wallet.util.MonetaryUtil;
import com.samourai.wallet.util.PrefsUtil;
import com.samourai.wallet.util.PrivKeyReader;
import com.samourai.wallet.util.TimeOutUtil;
import com.samourai.wallet.utxos.UTXOSActivity;
import com.samourai.wallet.whirlpool.WhirlpoolMain;
import com.samourai.wallet.whirlpool.WhirlpoolMeta;
import com.samourai.wallet.widgets.ItemDividerDecorator;
import com.samourai.whirlpool.client.wallet.AndroidWhirlpoolWalletService;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.crypto.BIP38PrivateKey;
import org.bitcoinj.crypto.MnemonicException;
import org.bitcoinj.script.Script;
import org.bouncycastle.util.encoders.Hex;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class BalanceActivity extends AppCompatActivity {

    private final static int SCAN_COLD_STORAGE = 2011;
    private final static int SCAN_QR = 2012;
    private static final String TAG = "BalanceActivity";


    private List<Tx> txs = null;
    private RecyclerView TxRecyclerView;
    private ProgressBar progressBar;
    private BalanceViewModel balanceViewModel;
    private int account = 0;

    private PoWTask powTask = null;
    private RicochetQueueTask ricochetQueueTask = null;
    private com.github.clans.fab.FloatingActionMenu menuFab;
    private SwipeRefreshLayout txSwipeLayout;
    private CollapsingToolbarLayout mCollapsingToolbar;
    private CompositeDisposable compositeDisposable = new CompositeDisposable();
    private Toolbar toolbar;
    private Menu menu;
    private ImageView menuTorIcon;
    private ProgressBar progressBarMenu;
    private View whirlpoolFab,sendFab,receiveFab,paynymFab;

    public static final String ACTION_INTENT = "com.samourai.wallet.BalanceFragment.REFRESH";
    protected BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, Intent intent) {

            if (ACTION_INTENT.equals(intent.getAction())) {
                if (progressBar != null) {
                    progressBar.setVisibility(View.VISIBLE);
                }
                final boolean notifTx = intent.getBooleanExtra("notifTx", false);
                final boolean fetch = intent.getBooleanExtra("fetch", false);

                final String rbfHash;
                final String blkHash;
                if (intent.hasExtra("rbf")) {
                    rbfHash = intent.getStringExtra("rbf");
                } else {
                    rbfHash = null;
                }
                if (intent.hasExtra("hash")) {
                    blkHash = intent.getStringExtra("hash");
                } else {
                    blkHash = null;
                }

                Handler handler = new Handler();
                handler.post(() -> {
                    refreshTx(notifTx, false, false);

                    if (BalanceActivity.this != null) {

                        if (rbfHash != null) {
                            new AlertDialog.Builder(BalanceActivity.this)
                                    .setTitle(R.string.app_name)
                                    .setMessage(rbfHash + "\n\n" + getString(R.string.rbf_incoming))
                                    .setCancelable(true)
                                    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {

                                            doExplorerView(rbfHash);

                                        }
                                    })
                                    .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {
                                            ;
                                        }
                                    }).show();

                        }

                    }
                });

                if (BalanceActivity.this != null && blkHash != null && PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.USE_TRUSTED_NODE, false) == true && TrustedNodeUtil.getInstance().isSet()) {

//                    BalanceActivity.this.runOnUiThread(new Runnable() {
//                    @Override
                    handler.post(new Runnable() {
                        public void run() {
                            if (powTask == null || powTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
                                powTask = new PoWTask();
                                powTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, blkHash);
                            }
                        }

                    });

                }

            }

        }
    };

    public static final String DISPLAY_INTENT = "com.samourai.wallet.BalanceFragment.DISPLAY";
    protected BroadcastReceiver receiverDisplay = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, Intent intent) {

            if (DISPLAY_INTENT.equals(intent.getAction())) {

                updateDisplay(true);

                List<UTXO> utxos = APIFactory.getInstance(BalanceActivity.this).getUtxos(false);
                for (UTXO utxo : utxos) {
                    List<MyTransactionOutPoint> outpoints = utxo.getOutpoints();
                    for (MyTransactionOutPoint out : outpoints) {

                        byte[] scriptBytes = out.getScriptBytes();
                        String address = null;
                        try {
                            if (Bech32Util.getInstance().isBech32Script(Hex.toHexString(scriptBytes))) {
                                address = Bech32Util.getInstance().getAddressFromScript(Hex.toHexString(scriptBytes));
                            } else {
                                address = new Script(scriptBytes).getToAddress(SamouraiWallet.getInstance().getCurrentNetworkParams()).toString();
                            }
                        } catch (Exception e) {
                        }
                        String path = APIFactory.getInstance(BalanceActivity.this).getUnspentPaths().get(address);
                        if (path != null && path.startsWith("M/1/")) {
                            continue;
                        }

                        final String hash = out.getHash().toString();
                        final int idx = out.getTxOutputN();
                        final long amount = out.getValue().longValue();

                        if (amount < BlockedUTXO.BLOCKED_UTXO_THRESHOLD &&
                                !BlockedUTXO.getInstance().contains(hash, idx) &&
                                !BlockedUTXO.getInstance().containsNotDusted(hash, idx)) {

//                            BalanceActivity.this.runOnUiThread(new Runnable() {
//                            @Override
                            Handler handler = new Handler();
                            handler.post(new Runnable() {
                                public void run() {

                                    String message = BalanceActivity.this.getString(R.string.dusting_attempt);
                                    message += "\n\n";
                                    message += BalanceActivity.this.getString(R.string.dusting_attempt_amount);
                                    message += " ";
                                    message += Coin.valueOf(amount).toPlainString();
                                    message += " BTC\n";
                                    message += BalanceActivity.this.getString(R.string.dusting_attempt_id);
                                    message += " ";
                                    message += hash + "-" + idx;

                                    AlertDialog.Builder dlg = new AlertDialog.Builder(BalanceActivity.this)
                                            .setTitle(R.string.dusting_tx)
                                            .setMessage(message)
                                            .setCancelable(false)
                                            .setPositiveButton(R.string.dusting_attempt_mark_unspendable, new DialogInterface.OnClickListener() {
                                                public void onClick(DialogInterface dialog, int whichButton) {

                                                    BlockedUTXO.getInstance().add(hash, idx, amount);

                                                }
                                            }).setNegativeButton(R.string.dusting_attempt_ignore, new DialogInterface.OnClickListener() {
                                                public void onClick(DialogInterface dialog, int whichButton) {

                                                    BlockedUTXO.getInstance().addNotDusted(hash, idx);

                                                }
                                            });
                                    if (!isFinishing()) {
                                        dlg.show();
                                    }

                                }
                            });

                        }

                    }

                }

            }

        }
    };

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_balance);
        balanceViewModel = ViewModelProviders.of(this).get(BalanceViewModel.class);
        makePaynymAvatarcache();
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        if ((getIntent().getExtras() != null && getIntent().getExtras().containsKey("_account"))) {
            account = getIntent().getExtras().getInt("_account");
        }

        TxRecyclerView = findViewById(R.id.rv_txes);
        progressBar = findViewById(R.id.progressBar);
        toolbar = findViewById(R.id.toolbar);
        mCollapsingToolbar = findViewById(R.id.toolbar_layout);
        txSwipeLayout = findViewById(R.id.tx_swipe_container);

        setSupportActionBar(toolbar);
        TxRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        Drawable drawable = this.getResources().getDrawable(R.drawable.divider);
        TxRecyclerView.addItemDecoration(new ItemDividerDecorator(drawable));
        menuFab = findViewById(R.id.fab_menu);
        txs = new ArrayList<>();
        whirlpoolFab = findViewById(R.id.whirlpool_fab);
        sendFab =  findViewById(R.id.send_fab);
        receiveFab =  findViewById(R.id.receive_fab);
        paynymFab =  findViewById(R.id.paynym_fab);

        findViewById(R.id.whirlpool_fab).setOnClickListener(view -> {
            Intent intent = new Intent(BalanceActivity.this, WhirlpoolMain.class);
            startActivity(intent);
            menuFab.toggle(true);
        });

        sendFab.setOnClickListener(view -> {
            Intent intent = new Intent(BalanceActivity.this, SendActivity.class);
            intent.putExtra("via_menu", true);
            intent.putExtra("_account", account);
            startActivity(intent);
            menuFab.toggle(true);
        });
        setBalance(0L, false);
        receiveFab.setOnClickListener(view -> {
            menuFab.toggle(true);

            try {
                HD_Wallet hdw = HD_WalletFactory.getInstance(BalanceActivity.this).get();

                if (hdw != null) {
                    Intent intent = new Intent(BalanceActivity.this, ReceiveActivity.class);
                    startActivity(intent);
                }


            } catch (IOException | MnemonicException.MnemonicLengthException e) {
            }
        });
        paynymFab.setOnClickListener(view -> {
            menuFab.toggle(true);
            Intent intent = new Intent(BalanceActivity.this, PayNymHome.class);
            startActivity(intent);
        });
        txSwipeLayout.setOnRefreshListener(() -> {
            refreshTx(false, true, false);
            txSwipeLayout.setRefreshing(false);
            progressBar.setVisibility(View.VISIBLE);
        });

        IntentFilter filter = new IntentFilter(ACTION_INTENT);
        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiver, filter);
        IntentFilter filterDisplay = new IntentFilter(DISPLAY_INTENT);
        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiverDisplay, filterDisplay);

        if (!PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || !PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtil.getInstance(BalanceActivity.this).showRequestPermissionsInfoAlertDialog(PermissionsUtil.READ_WRITE_EXTERNAL_PERMISSION_CODE);
        }
        if (!PermissionsUtil.getInstance(BalanceActivity.this).hasPermission(Manifest.permission.CAMERA)) {
            PermissionsUtil.getInstance(BalanceActivity.this).showRequestPermissionsInfoAlertDialog(PermissionsUtil.CAMERA_PERMISSION_CODE);
        }

        if (PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_CLAIMED, false) == true && PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_FEATURED_SEGWIT, false) == false) {
            doFeaturePayNymUpdate();
        } else if (PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_CLAIMED, false) == false &&
                PrefsUtil.getInstance(BalanceActivity.this).getValue(PrefsUtil.PAYNYM_REFUSED, false) == false) {
            doClaimPayNym();
        } else {
        }

        if (RicochetMeta.getInstance(BalanceActivity.this).getQueue().size() > 0) {
            if (ricochetQueueTask == null || ricochetQueueTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
                ricochetQueueTask = new RicochetQueueTask();
                ricochetQueueTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
            }
        }

        if (!AppUtil.getInstance(BalanceActivity.this).isClipboardSeen()) {
            doClipboardCheck();
        }


        if (!AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            startService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }
        setUpTor();
        initViewModel();
        progressBar.setVisibility(View.VISIBLE);

        if (account == 0) {
            final Handler delayedHandler = new Handler();
            delayedHandler.postDelayed(() -> {

                boolean notifTx = false;
                Bundle extras = getIntent().getExtras();
                if (extras != null && extras.containsKey("notifTx")) {
                    notifTx = extras.getBoolean("notifTx");
                }

                refreshTx(notifTx, false, true);

                updateDisplay(false);
            }, 100L);
            getSupportActionBar().setIcon(R.drawable.ic_samourai_logo_toolbar);
            balanceViewModel.loadOfflineData();
        } else {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            receiveFab.setVisibility(View.GONE);
            whirlpoolFab.setVisibility(View.GONE);
            paynymFab.setVisibility(View.GONE);
            new Handler().postDelayed(() -> updateDisplay(true), 600L);

        }
        updateDisplay(false);
        checkDeepLinks();
    }

    private void checkDeepLinks() {
        Bundle bundle = getIntent().getExtras();
        if (bundle == null) {
            return;
        }
        if (bundle.containsKey("pcode") || bundle.containsKey("uri") || bundle.containsKey("amount")) {
            if (balanceViewModel.getBalance().getValue() != null)
                bundle.putLong("balance", balanceViewModel.getBalance().getValue());
            Intent intent = new Intent(this, SendActivity.class);
            intent.putExtra("_account",account);
            intent.putExtras(bundle);
            startActivity(intent);
        }

    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    private void initViewModel() {
        TxAdapter adapter = new TxAdapter(getApplicationContext(), new ArrayList<>());
        adapter.setHasStableIds(true);
        adapter.setClickListener((position, tx) -> txDetails(tx));

        TxRecyclerView.setAdapter(adapter);

        balanceViewModel.getBalance().observe(this, balance -> {
            if (balance < 0) {
                return;
            }
            if (balanceViewModel.getSatState().getValue() != null) {
                setBalance(balance, balanceViewModel.getSatState().getValue());
            } else {
                setBalance(balance, false);
            }
        });
        adapter.setTxes(balanceViewModel.getTxs().getValue());
        setBalance(balanceViewModel.getBalance().getValue(), false);

        balanceViewModel.getSatState().observe(this, state -> {
            if (state == null) {
                state = false;
            }
            setBalance(balanceViewModel.getBalance().getValue(), state);
            adapter.toggleDisplayUnit(state);
        });
        balanceViewModel.getTxs().observe(this, new Observer<List<Tx>>() {
            @Override
            public void onChanged(@Nullable List<Tx> list) {
                adapter.setTxes(list);
            }
        });
        mCollapsingToolbar.setOnClickListener(view -> balanceViewModel.toggleSat());

    }

    private void setBalance(Long balance, boolean isSat) {
        if (balance == null) {
            return;
        }

        if (getSupportActionBar() != null) {
            TransitionManager.beginDelayedTransition(mCollapsingToolbar, new ChangeBounds());

            String displayAmount = "".concat(isSat ? getSatoshiDisplayAmount(balance) : getBTCDisplayAmount(balance));
            String Unit = isSat ? getSatoshiDisplayUnits() : getBTCDisplayUnits();

            displayAmount = displayAmount.concat(" ").concat(Unit);
            toolbar.setTitle(displayAmount);
            setTitle(displayAmount);
            mCollapsingToolbar.setTitle(displayAmount);

        }


        Log.i(TAG, "setBalance: ".concat(getBTCDisplayAmount(balance)));

    }

    @Override
    public void onResume() {
        super.onResume();

//        IntentFilter filter = new IntentFilter(ACTION_INTENT);
//        LocalBroadcastManager.getInstance(BalanceActivity.this).registerReceiver(receiver, filter);

        AppUtil.getInstance(BalanceActivity.this).checkTimeOut();

        Intent intent = new Intent("com.samourai.wallet.MainActivity2.RESTART_SERVICE");
        LocalBroadcastManager.getInstance(BalanceActivity.this).sendBroadcast(intent);

    }

    public View createTag(String text){
        float scale = getResources().getDisplayMetrics().density;
        LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        TextView textView = new TextView(getApplicationContext());
        textView.setText(text);
        textView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
        textView.setLayoutParams(lparams);
        textView.setBackgroundResource(R.drawable.tag_round_shape);
        textView.setPadding((int) (8 * scale + 0.5f), (int) (6 * scale + 0.5f), (int) (8 * scale + 0.5f), (int) (6 * scale + 0.5f));
        textView.setTypeface(Typeface.DEFAULT_BOLD);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 11);
        return textView;
    }

    @Override
    public void onPause() {
        super.onPause();

//        ibQuickSend.collapse();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            stopService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }

    }


    private void makePaynymAvatarcache() {
        try {

            ArrayList<String> paymentCodes = new ArrayList<>(BIP47Meta.getInstance().getSortedByLabels(false, true));
            for (String code : paymentCodes) {
                Picasso.with(getBaseContext())
                        .load(com.samourai.wallet.bip47.paynym.WebUtil.PAYNYM_API + code + "/avatar").fetch(new Callback() {
                    @Override
                    public void onSuccess() {
                        /*NO OP*/
                    }

                    @Override
                    public void onError() {
                        /*NO OP*/
                    }
                });
            }

        } catch (Exception ignored) {

        }
    }

    @Override
    public void onDestroy() {

        LocalBroadcastManager.getInstance(BalanceActivity.this).unregisterReceiver(receiver);
        LocalBroadcastManager.getInstance(BalanceActivity.this).unregisterReceiver(receiverDisplay);

        if (AppUtil.getInstance(BalanceActivity.this.getApplicationContext()).isServiceRunning(WebSocketService.class)) {
            stopService(new Intent(BalanceActivity.this.getApplicationContext(), WebSocketService.class));
        }

        if(isFinishing()){
            // disconnect Whirlpool on app exit
            AndroidWhirlpoolWalletService.getInstance().closeWallet();
        }

        super.onDestroy();

        if(compositeDisposable != null && !compositeDisposable.isDisposed()) {
            compositeDisposable.dispose();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);

        menu.findItem(R.id.action_refresh).setVisible(false);
        menu.findItem(R.id.action_share_receive).setVisible(false);
        menu.findItem(R.id.action_ricochet).setVisible(false);
        menu.findItem(R.id.action_empty_ricochet).setVisible(false);
        menu.findItem(R.id.action_sign).setVisible(false);
        menu.findItem(R.id.action_fees).setVisible(false);
        menu.findItem(R.id.action_batch).setVisible(false);

        WhirlpoolMeta.getInstance(getApplicationContext());
        if (account == WhirlpoolMeta.getInstance(getApplicationContext()).getWhirlpoolPostmix()) {
            menu.findItem(R.id.action_network_dashboard).setVisible(false);
            MenuItem item = menu.findItem(R.id.action_menu_account);
            item.setActionView(createTag(" POST-MIX "));
            item.setVisible(true);
            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

        }
        this.menu = menu;

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        if(id == android.R.id.home){
            this.finish();
            return super.onOptionsItemSelected(item);
        }
        // noinspection SimplifiableIfStatement
        if (id == R.id.action_network_dashboard) {
            startActivity(new Intent(this, NetworkDashboard.class));
        }    // noinspection SimplifiableIfStatement
        if (id == R.id.action_copy_cahoots) {
            ClipboardManager clipboard = (ClipboardManager)  getSystemService(Context.CLIPBOARD_SERVICE);
            if(clipboard.hasPrimaryClip())    {
                ClipData.Item clipItem = clipboard.getPrimaryClip().getItemAt(0);

                if(Cahoots.isCahoots(clipItem.getText().toString().trim())){
                    Intent cahootIntent = new Intent(this, ManualCahootsActivity.class);
                    cahootIntent.putExtra("payload",clipItem.getText().toString().trim());
                    startActivity(cahootIntent);
                }else {
                    Toast.makeText(this,R.string.cannot_process_cahoots,Toast.LENGTH_SHORT).show();
                }
            }
            else    {
                Toast.makeText(this,R.string.clipboard_empty,Toast.LENGTH_SHORT).show();
            }
        }
        if (id == R.id.action_settings) {
            doSettings();
        } else if (id == R.id.action_support) {
            doSupport();
        } else if (id == R.id.action_sweep) {
            if (!AppUtil.getInstance(BalanceActivity.this).isOfflineMode()) {
{'fraction_non_alphanumeric': 0.0999776873830733, 'fraction_numerical': 0.002299915898597738, 'mean_word_length': 2.224706663714855, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 104, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4332057', 'n_tokens_mistral': 15716, 'n_tokens_neox': 15261, 'n_words': 2330}