/* * Copyright 2014 http://Bither.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.bither.fragment.cold; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.Spannable; import android.text.SpannableString; import android.text.style.TypefaceSpan; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.Animator.AnimatorListener; import com.nineoldandroids.animation.ObjectAnimator; import net.bither.R; import net.bither.bitherj.BitherjSettings; import net.bither.bitherj.core.Address; import net.bither.bitherj.core.AddressManager; import net.bither.bitherj.core.HDAccount; import net.bither.bitherj.crypto.SecureCharSequence; import net.bither.bitherj.utils.Utils; import net.bither.model.Check; import net.bither.model.Check.CheckListener; import net.bither.preference.AppSharedPreference; import net.bither.ui.base.CheckHeaderView; import net.bither.ui.base.CheckHeaderView.CheckHeaderViewListener; import net.bither.ui.base.WrapLayoutParamsForAnimator; import net.bither.ui.base.dialog.DialogAddressFull; import net.bither.util.CheckUtil; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; public class CheckFragment extends Fragment implements CheckHeaderViewListener { private static final String HDMKeychainAsAddressFaker = "HDM Keychain"; private static final int PrivateKeyCheckThreadCount = 1; private static final int ListExpandAnimDuration = 500; private FrameLayout flContainer; private CheckHeaderView vCheckHeader; private FrameLayout fl; private ListView lv; private int checkCount; private int checkFinishedCount; private ArrayList<CheckPoint> checkPoints = new ArrayList<CheckPoint>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { int resource = R.layout.fragment_check_cold; View view = inflater.inflate(resource, container, false); flContainer = (FrameLayout) view.findViewById(R.id.fl_container); vCheckHeader = (CheckHeaderView) view.findViewById(R.id.v_check_header); lv = (ListView) view.findViewById(R.id.lv); fl = (FrameLayout) view.findViewById(R.id.fl); lv.setStackFromBottom(false); lv.setAdapter(adapter); vCheckHeader.setListener(this); return view; } private void check(final List<Check> checks, final int threadCount) { checkCount = checks.size(); checkFinishedCount = 0; vCheckHeader.setTotalCheckCount(checkCount); vCheckHeader.setPassedCheckCount(0); lv.postDelayed(new Runnable() { @Override public void run() { CheckUtil.runChecks(checks, threadCount); } }, 600); } private class CheckPoint implements CheckListener { private boolean waiting; private boolean checking; private boolean result; private String address; public CheckPoint(String address) { waiting = true; this.address = address; } @Override public void onCheckBegin(Check check) { checking = true; waiting = false; adapter.notifyDataSetChanged(); final int index = checkPoints.indexOf(this); int itemHeight = lv.getChildAt(0).getHeight(); int lvHeight = lv.getHeight() - lv.getPaddingBottom() - lv.getPaddingTop(); lv.setSelectionFromTop(index, lvHeight - itemHeight); } @Override public void onCheckEnd(Check check, boolean success) { checking = false; result = success; checkFinishedCount++; if (success) { vCheckHeader.addPassedCheckCount(); } adapter.notifyDataSetChanged(); if (checkFinishedCount >= checkCount) { vCheckHeader.postDelayed(new Runnable() { @Override public void run() { vCheckHeader.stop(); } }, 600); } } public boolean isHDM() { return Utils.compareString(address, HDMKeychainAsAddressFaker); } public boolean isHDAccount() { return Utils.compareString(address, HDAccount.HDAccountPlaceHolder); } public boolean isHDAccountCold() { return Utils.compareString(address, HDAccount.HDAccountMonitoredPlaceHolder) && AppSharedPreference.getInstance().getAppMode() == BitherjSettings.AppMode .COLD; } public boolean isWaiting() { return waiting; } public boolean isChecking() { return checking; } public boolean getResult() { return result; } public String getAddress() { return address; } } @Override public void beginCheck(final SecureCharSequence password) { final List<Address> addresses = AddressManager.getInstance().getPrivKeyAddresses(); checkPoints.clear(); final ArrayList<Check> checks = new ArrayList<Check>(); if (AddressManager.getInstance().hasHDAccountCold() && AppSharedPreference.getInstance().getAppMode() == BitherjSettings.AppMode.COLD) { CheckPoint point = new CheckPoint(HDAccount.HDAccountMonitoredPlaceHolder); checkPoints.add(point); final SecureCharSequence p = new SecureCharSequence(password); checks.add(new Check(R.string.hd_account_cold_address_list_label, new Check .ICheckAction() { @Override public boolean check() { return AddressManager.getInstance().getHDAccountCold().checkWithPassword(p); } }).setCheckListener(point)); } if (AddressManager.getInstance().hasHDAccountHot()) { CheckPoint point = new CheckPoint(HDAccount.HDAccountPlaceHolder); checkPoints.add(point); checks.add(CheckUtil.initCheckForHDAccount(AddressManager.getInstance().getHDAccountHot (), new SecureCharSequence(password)).setCheckListener(point)); } if (AddressManager.getInstance().hasHDMKeychain()) { CheckPoint point = new CheckPoint(HDMKeychainAsAddressFaker); checkPoints.add(point); checks.add(CheckUtil.initCheckForHDMKeychain(AddressManager.getInstance() .getHdmKeychain(), new SecureCharSequence(password)).setCheckListener(point)); } for (int i = 0; i < addresses.size(); i++) { Address address = addresses.get(i); CheckPoint point = new CheckPoint(address.getAddress()); checkPoints.add(point); checks.add(CheckUtil.initCheckForPrivateKey(address, new SecureCharSequence(password) ).setCheckListener(point)); } password.wipe(); adapter.notifyDataSetChanged(); if (lv.getHeight() <= 0) { int lvHeight = flContainer.getHeight() - vCheckHeader.getHeight(); ObjectAnimator animator = ObjectAnimator.ofInt( new WrapLayoutParamsForAnimator(fl), "height", lvHeight) .setDuration(ListExpandAnimDuration); animator.addListener(new AnimatorListener() { @Override public void onAnimationEnd(Animator animation) { check(checks, PrivateKeyCheckThreadCount); } @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } }); animator.start(); } else { check(checks, PrivateKeyCheckThreadCount); } } public void check() { vCheckHeader.check(); } private BaseAdapter adapter = new BaseAdapter() { @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder h; if (convertView == null) { convertView = LayoutInflater.from(getActivity()).inflate( R.layout.list_item_check, null); h = new ViewHolder(convertView); } else { h = (ViewHolder) convertView.getTag(); } CheckPoint point = getItem(position); if (point.isHDAccount()) { h.tv.setText(R.string.address_group_hd); } else if (point.isHDM()) { int resourceId = R.string.hdm_keychain_check_title_cold; if (AppSharedPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { resourceId = R.string.hdm_keychain_check_title_hot; } h.tv.setText(resourceId); } else if (point.isHDAccountCold()) { h.tv.setText(R.string.hd_account_cold_address_list_label); } else { h.tv.setText(getSpannableStringFromAddress(point.getAddress())); } if (!point.isHDM() && !point.isHDAccount() && !point.isHDAccountCold()) { h.ibtnFull.setOnClickListener(new AddressFullClick(point.getAddress())); h.ibtnFull.setVisibility(View.VISIBLE); } else { h.ibtnFull.setOnClickListener(null); h.ibtnFull.setVisibility(View.INVISIBLE); } if (point.isWaiting()) { h.pb.setVisibility(View.GONE); h.iv.setVisibility(View.GONE); } else { if (point.isChecking()) { h.pb.setVisibility(View.VISIBLE); h.iv.setVisibility(View.GONE); } else { if (point.getResult()) { h.iv.setImageResource(R.drawable.checkmark); } else { h.iv.setImageResource(R.drawable.check_failed); } h.iv.setVisibility(View.VISIBLE); h.pb.setVisibility(View.GONE); } } return convertView; } private SpannableString getSpannableStringFromAddress(String address) { address = Utils.shortenAddress(address); String a = address.substring(0, 4); String str = String.format( getString(R.string.check_address_private_key_title), address); int indexOfAddress = str.indexOf(a); SpannableString spannable = new SpannableString(str); spannable.setSpan(new TypefaceSpan("monospace"), indexOfAddress, indexOfAddress + 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spannable; } @Override public long getItemId(int position) { return position; } @Override public CheckPoint getItem(int position) { return checkPoints.get(position); } @Override public int getCount() { return checkPoints.size(); } class ViewHolder { TextView tv; ProgressBar pb; ImageView iv; ImageButton ibtnFull; public ViewHolder(View v) { tv = (TextView) v.findViewById(R.id.tv_check_title); pb = (ProgressBar) v.findViewById(R.id.pb_check); iv = (ImageView) v.findViewById(R.id.iv_check_state); ibtnFull = (ImageButton) v.findViewById(R.id.ibtn_address_full); v.setTag(this); } } class AddressFullClick implements OnClickListener { private String address; public AddressFullClick(String address) { this.address = address; } @Override public void onClick(View v) { LinkedHashMap<String, Long> map = new LinkedHashMap<String, Long>(); map.put(address, 0L); DialogAddressFull dialog = new DialogAddressFull(getActivity(), map); dialog.show(v); } } }; }