Merge pull request #14090 from brave/support-solana-account-creation-import

feat(wallet): implement solana account creation and selection
This commit is contained in:
Pavneet Singh
2022-07-09 00:23:46 +05:30
committed by GitHub
28 changed files with 785 additions and 237 deletions
@@ -18,6 +18,7 @@ public abstract class BraveFeatureList {
public static final String ENABLE_FORCE_DARK = "enable-force-dark";
public static final String ENABLE_TAB_GROUPS = "enable-tab-groups";
public static final String ENABLE_TAB_GRID = "enable-tab-grid-layout";
public static final String BRAVE_WALLET_SOLANA = "BraveWalletSolana";
public static void enableFeature(
String featureName, boolean enabled, boolean fallbackToDefault) {
@@ -1249,18 +1249,19 @@ public abstract class BraveActivity<C extends ChromeActivityComponent> extends C
return;
}
walletModel.resetServices(null, null, null, null, null, null, null, null);
walletModel.resetServices(
getApplicationContext(), null, null, null, null, null, null, null, null);
}
private void setupWalletModel() {
if (walletModel == null) {
walletModel = new WalletModel(mKeyringService, mBlockchainRegistry, mJsonRpcService,
mTxService, mEthTxManagerProxy, mSolanaTxManagerProxy, mAssetRatioService,
mBraveWalletService);
walletModel = new WalletModel(getApplicationContext(), mKeyringService,
mBlockchainRegistry, mJsonRpcService, mTxService, mEthTxManagerProxy,
mSolanaTxManagerProxy, mAssetRatioService, mBraveWalletService);
} else {
walletModel.resetServices(mKeyringService, mBlockchainRegistry, mJsonRpcService,
mTxService, mEthTxManagerProxy, mSolanaTxManagerProxy, mAssetRatioService,
mBraveWalletService);
walletModel.resetServices(getApplicationContext(), mKeyringService, mBlockchainRegistry,
mJsonRpcService, mTxService, mEthTxManagerProxy, mSolanaTxManagerProxy,
mAssetRatioService, mBraveWalletService);
}
setupObservers();
}
@@ -5,10 +5,14 @@
package org.chromium.chrome.browser.app.domain;
import android.content.Context;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import com.google.android.gms.common.util.ArrayUtils;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.AssetRatioService;
import org.chromium.brave_wallet.mojom.BlockchainRegistry;
@@ -24,12 +28,17 @@ import org.chromium.brave_wallet.mojom.SolanaTxManagerProxy;
import org.chromium.brave_wallet.mojom.TransactionInfo;
import org.chromium.brave_wallet.mojom.TransactionStatus;
import org.chromium.brave_wallet.mojom.TxService;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.BraveFeatureList;
import org.chromium.chrome.browser.crypto_wallet.activities.BraveWalletDAppsActivity;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import org.chromium.chrome.browser.crypto_wallet.util.PendingTxHelper;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.mojo.bindings.Callbacks.Callback1;
import org.chromium.url.internal.mojom.Origin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -53,16 +62,18 @@ public class CryptoModel {
public final LiveData<BraveWalletDAppsActivity.ActivityType> mProcessNextDAppsRequest =
_mProcessNextDAppsRequest;
private final Object mLock = new Object();
private Context mContext;
private NetworkModel mNetworkModel;
// Todo: create a models for portfolio
// Todo: create method to create and return new models for Asset, Account,
// TransactionConfirmation
public CryptoModel(TxService mTxService, KeyringService mKeyringService,
public CryptoModel(Context context, TxService mTxService, KeyringService mKeyringService,
BlockchainRegistry mBlockchainRegistry, JsonRpcService mJsonRpcService,
EthTxManagerProxy mEthTxManagerProxy, SolanaTxManagerProxy mSolanaTxManagerProxy,
BraveWalletService mBraveWalletService, AssetRatioService mAssetRatioService) {
mContext = context;
this.mTxService = mTxService;
this.mKeyringService = mKeyringService;
this.mBlockchainRegistry = mBlockchainRegistry;
@@ -76,11 +87,12 @@ public class CryptoModel {
mNetworkModel = new NetworkModel(mJsonRpcService, mSharedData);
}
public void resetServices(TxService mTxService, KeyringService mKeyringService,
public void resetServices(Context context, TxService mTxService, KeyringService mKeyringService,
BlockchainRegistry mBlockchainRegistry, JsonRpcService mJsonRpcService,
EthTxManagerProxy mEthTxManagerProxy, SolanaTxManagerProxy mSolanaTxManagerProxy,
BraveWalletService mBraveWalletService, AssetRatioService mAssetRatioService) {
synchronized (mLock) {
mContext = context;
this.mTxService = mTxService;
this.mKeyringService = mKeyringService;
this.mBlockchainRegistry = mBlockchainRegistry;
@@ -221,6 +233,19 @@ public class CryptoModel {
}
}
public List<CryptoAccountTypeInfo> getSupportedCryptoAccountTypes() {
List<CryptoAccountTypeInfo> cryptoAccountTypeInfos = new ArrayList<>();
cryptoAccountTypeInfos.add(new CryptoAccountTypeInfo(
mContext.getString(R.string.brave_wallet_create_account_ethereum_description),
"Ethereum", CoinType.ETH, R.drawable.eth));
if (isSolanaEnabled()) {
cryptoAccountTypeInfos.add(new CryptoAccountTypeInfo(
mContext.getString(R.string.brave_wallet_create_account_solana_description),
"Solana", CoinType.SOL, R.drawable.ic_sol_asset_icon));
}
return cryptoAccountTypeInfos;
}
public PendingTxHelper getPendingTxHelper() {
return mPendingTxHelper;
}
@@ -233,6 +258,15 @@ public class CryptoModel {
return mNetworkModel;
}
public boolean isSolanaEnabled() {
return ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_WALLET_SOLANA);
}
public void updateCoinType() {
mBraveWalletService.getSelectedCoin(
coinType -> { _mCoinTypeMutableLiveData.postValue(coinType); });
}
/*
* A container class to share the required data throughout the domain model classes.
* Note: It should only be used/accessed within the domain package
@@ -253,5 +287,25 @@ public class CryptoModel {
}
return mNetworkModel.mChainId.getValue();
}
@Override
public Context getContext() {
return mContext;
}
@Override
public LiveData<Integer> getCoinTypeLd() {
return mCoinTypeMutableLiveData;
}
@Override
public String[] getEnabledKeyrings() {
ArrayList<String> keyRings = new ArrayList<>();
keyRings.add(BraveWalletConstants.DEFAULT_KEYRING_ID);
if (isSolanaEnabled()) {
keyRings.add(BraveWalletConstants.SOLANA_KEYRING_ID);
}
return keyRings.toArray(new String[0]);
}
}
}
@@ -0,0 +1,14 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.app.domain;
import android.content.Context;
import androidx.lifecycle.LiveData;
public interface CryptoModelActions {
void updateCoinType();
}
@@ -1,6 +1,13 @@
package org.chromium.chrome.browser.app.domain;
import android.content.Context;
import androidx.lifecycle.LiveData;
public interface CryptoSharedData {
int getCoinType();
String getChainId();
Context getContext();
LiveData<Integer> getCoinTypeLd();
String[] getEnabledKeyrings();
}
@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.app.domain;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
@@ -12,35 +13,58 @@ import androidx.lifecycle.MutableLiveData;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.BraveWalletConstants;
import org.chromium.brave_wallet.mojom.BraveWalletService;
import org.chromium.brave_wallet.mojom.CoinType;
import org.chromium.brave_wallet.mojom.KeyringInfo;
import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.brave_wallet.mojom.KeyringServiceObserver;
import org.chromium.chrome.browser.crypto_wallet.util.AccountsPermissionsHelper;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.mojo.bindings.Callbacks;
import org.chromium.mojo.system.MojoException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
public class KeyringModel implements KeyringServiceObserver {
private static final int NO_COIN_TYPE = Integer.MIN_VALUE;
private KeyringService mKeyringService;
private BraveWalletService mBraveWalletService;
private MutableLiveData<KeyringInfo> _mKeyringInfoLiveData;
public LiveData<KeyringInfo> mKeyringInfoLiveData;
private MutableLiveData<KeyringInfo[]> _mKeyringInfosLiveData;
public LiveData<KeyringInfo[]> mKeyringInfosLiveData;
private MutableLiveData<KeyringInfo> _mSelectedCoinKeyringInfoLiveData;
public LiveData<KeyringInfo> mSelectedCoinKeyringInfoLiveData;
private final MutableLiveData<AccountInfo> _mSelectedAccount;
public LiveData<List<AccountInfo>> mAccountInfos;
private final MutableLiveData<List<AccountInfo>> _mAccountInfos;
// Prefer using getSelectedAccountOrAccountPerOrigin, especially for dapps
public LiveData<AccountInfo> mSelectedAccount;
private CryptoSharedData mSharedData;
private AccountsPermissionsHelper mAccountsPermissionsHelper;
private final Object mLock = new Object();
private CryptoModelActions mCryptoModelActions;
private HashMap<Integer, String> mKeyringToCoin;
public KeyringModel(KeyringService keyringService, CryptoSharedData sharedData,
BraveWalletService braveWalletService) {
BraveWalletService braveWalletService, CryptoModelActions cryptoModelActions) {
mKeyringToCoin = new HashMap<>();
mKeyringService = keyringService;
mBraveWalletService = braveWalletService;
mSharedData = sharedData;
_mKeyringInfoLiveData = new MutableLiveData<>(null);
mKeyringInfoLiveData = _mKeyringInfoLiveData;
_mKeyringInfosLiveData = new MutableLiveData<>(new KeyringInfo[0]);
mKeyringInfosLiveData = _mKeyringInfosLiveData;
_mSelectedAccount = new MutableLiveData<>();
mSelectedAccount = _mSelectedAccount;
mCryptoModelActions = cryptoModelActions;
_mSelectedCoinKeyringInfoLiveData = new MutableLiveData<>(null);
mSelectedCoinKeyringInfoLiveData = _mSelectedCoinKeyringInfoLiveData;
_mAccountInfos = new MutableLiveData<>(Collections.emptyList());
mAccountInfos = _mAccountInfos;
initState();
}
public void init() {
@@ -52,32 +76,39 @@ public class KeyringModel implements KeyringServiceObserver {
}
}
private void update() {
private void update(int coinType) {
synchronized (mLock) {
if (mKeyringService == null) {
return;
}
mKeyringService.getKeyringInfo(BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
_mKeyringInfoLiveData.postValue(keyringInfo);
mKeyringService.getSelectedAccount(mSharedData.getCoinType(), accountAddress -> {
mKeyringService.getKeyringInfo(getSelectedCoinKeyringId(coinType),
keyringInfo -> { _mSelectedCoinKeyringInfoLiveData.postValue(keyringInfo); });
mKeyringService.getKeyringsInfo(mSharedData.getEnabledKeyrings(), keyringInfos -> {
List<AccountInfo> accountInfos = getAccountInfosFromKeyrings(keyringInfos);
_mAccountInfos.postValue(accountInfos);
_mKeyringInfosLiveData.postValue(keyringInfos);
mKeyringService.getSelectedAccount(coinType, accountAddress -> {
if (accountAddress != null && !accountAddress.isEmpty()) {
AccountInfo selectedAccountInfo = null;
for (AccountInfo accountInfo : keyringInfo.accountInfos) {
for (AccountInfo accountInfo : accountInfos) {
if (accountInfo.address.equals(accountAddress)) {
selectedAccountInfo = accountInfo;
break;
}
}
_mSelectedAccount.postValue(selectedAccountInfo);
} else if (keyringInfo.accountInfos.length > 0) {
_mSelectedAccount.postValue(keyringInfo.accountInfos[0]);
} else if (accountInfos.size() > 0) {
_mSelectedAccount.postValue(accountInfos.get(0));
}
});
});
}
}
private void update() {
mBraveWalletService.getSelectedCoin(coinType -> { update(coinType); });
}
private void updateSelectedAccountPerOriginOrFirst(KeyringInfo keyringInfo) {
mAccountsPermissionsHelper = new AccountsPermissionsHelper(
mBraveWalletService, keyringInfo.accountInfos, Utils.getCurrentMojomOrigin());
@@ -111,7 +142,8 @@ public class KeyringModel implements KeyringServiceObserver {
_mSelectedAccount.setValue(null);
mKeyringService.getSelectedAccount(mSharedData.getCoinType(), accountAddress -> {
if (accountAddress == null) {
mKeyringService.getKeyringInfo(BraveWalletConstants.DEFAULT_KEYRING_ID,
mKeyringService.getKeyringInfo(
getSelectedCoinKeyringId(mSharedData.getCoinType()),
keyringInfo -> { updateSelectedAccountPerOriginOrFirst(keyringInfo); });
} else {
update();
@@ -126,12 +158,15 @@ public class KeyringModel implements KeyringServiceObserver {
if (mKeyringService == null) {
return;
}
mKeyringService.setSelectedAccount(accountAddress, coin, isAccountSelected -> {});
mKeyringService.setSelectedAccount(accountAddress, coin, isAccountSelected -> {
mBraveWalletService.setSelectedCoin(coin);
mCryptoModelActions.updateCoinType();
});
}
}
public KeyringInfo getKeyringInfo() {
return _mKeyringInfoLiveData.getValue();
return getSelectedCoinKeyringInfo(mSharedData.getCoinType());
}
public void resetService(KeyringService keyringService, BraveWalletService braveWalletService) {
@@ -148,6 +183,68 @@ public class KeyringModel implements KeyringServiceObserver {
}
}
public void getAccounts(Callbacks.Callback1<AccountInfo[]> callback1) {
mKeyringService.getKeyringsInfo(mSharedData.getEnabledKeyrings(), keyringInfos -> {
List<AccountInfo> accountInfos = getAccountInfosFromKeyrings(keyringInfos);
callback1.call(accountInfos.toArray(new AccountInfo[0]));
});
}
@NonNull
private List<AccountInfo> getAccountInfosFromKeyrings(KeyringInfo[] keyringInfos) {
List<AccountInfo> accountInfos = new ArrayList<>();
for (KeyringInfo keyringInfo : keyringInfos) {
accountInfos.addAll(Arrays.asList(keyringInfo.accountInfos));
}
return accountInfos;
}
public void addAccount(String accountName, @CoinType.EnumType int coinType,
Callbacks.Callback1<Boolean> callback) {
final AccountInfo[] finalAccountInfos =
getAccountInfosFromKeyrings(_mKeyringInfosLiveData.getValue())
.toArray(new AccountInfo[0]);
mKeyringService.addAccount(accountName, coinType, result -> {
if (result) {
boolean hasNoExistingAccountType = true;
for (AccountInfo accountInfo : finalAccountInfos) {
hasNoExistingAccountType = !(accountInfo.coin == coinType);
if (hasNoExistingAccountType) break;
}
if (hasNoExistingAccountType) {
mKeyringService.getKeyringInfo(
getSelectedCoinKeyringId(coinType), updatedKeyringInfo -> {
for (AccountInfo accountInfo : updatedKeyringInfo.accountInfos) {
if (accountInfo.coin == coinType) {
setSelectedAccount(accountInfo.address, coinType);
break;
}
}
});
}
}
mCryptoModelActions.updateCoinType();
callback.call(result);
});
}
private KeyringInfo getSelectedCoinKeyringInfo(int coinType) {
String selectedCoinKeyringId = getSelectedCoinKeyringId(coinType);
for (KeyringInfo keyringInfo : _mKeyringInfosLiveData.getValue()) {
if (keyringInfo.id.equals(selectedCoinKeyringId)) return keyringInfo;
}
return null;
}
private String getSelectedCoinKeyringId(int coinType) {
return mKeyringToCoin.get(coinType);
}
private void initState() {
mKeyringToCoin.put(CoinType.ETH, BraveWalletConstants.DEFAULT_KEYRING_ID);
mKeyringToCoin.put(CoinType.SOL, BraveWalletConstants.SOLANA_KEYRING_ID);
}
@Override
public void keyringCreated(String keyringId) {
update();
@@ -188,7 +285,7 @@ public class KeyringModel implements KeyringServiceObserver {
@Override
public void selectedAccountChanged(int coin) {
update();
update(coin);
}
@Override
@@ -5,14 +5,18 @@
package org.chromium.chrome.browser.app.domain;
import android.content.Context;
import org.chromium.brave_wallet.mojom.AssetRatioService;
import org.chromium.brave_wallet.mojom.BlockchainRegistry;
import org.chromium.brave_wallet.mojom.BraveWalletService;
import org.chromium.brave_wallet.mojom.EthTxManagerProxy;
import org.chromium.brave_wallet.mojom.JsonRpcService;
import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.brave_wallet.mojom.SolanaProvider;
import org.chromium.brave_wallet.mojom.SolanaTxManagerProxy;
import org.chromium.brave_wallet.mojom.TxService;
import org.chromium.brave_wallet.mojom.WalletHandler;
// Under development, some parts not tested so use with caution
// A container for all the native services and APIs
@@ -28,11 +32,15 @@ public class WalletModel {
private final CryptoModel mCryptoModel;
private final DappsModel mDappsModel;
private final KeyringModel mKeyringModel;
private Context mContext;
private CryptoActions mCryptoActions;
public WalletModel(KeyringService keyringService, BlockchainRegistry blockchainRegistry,
JsonRpcService jsonRpcService, TxService txService, EthTxManagerProxy ethTxManagerProxy,
public WalletModel(Context context, KeyringService keyringService,
BlockchainRegistry blockchainRegistry, JsonRpcService jsonRpcService,
TxService txService, EthTxManagerProxy ethTxManagerProxy,
SolanaTxManagerProxy solanaTxManagerProxy, AssetRatioService assetRatioService,
BraveWalletService braveWalletService) {
mContext = context;
mKeyringService = keyringService;
mBlockchainRegistry = blockchainRegistry;
mJsonRpcService = jsonRpcService;
@@ -41,20 +49,23 @@ public class WalletModel {
mSolanaTxManagerProxy = solanaTxManagerProxy;
mAssetRatioService = assetRatioService;
mBraveWalletService = braveWalletService;
mCryptoModel = new CryptoModel(mTxService, mKeyringService, mBlockchainRegistry,
mCryptoActions = new CryptoActions();
mCryptoModel = new CryptoModel(mContext, mTxService, mKeyringService, mBlockchainRegistry,
mJsonRpcService, mEthTxManagerProxy, mSolanaTxManagerProxy, mBraveWalletService,
mAssetRatioService);
mDappsModel = new DappsModel(
mJsonRpcService, mBraveWalletService, mCryptoModel.getPendingTxHelper());
mKeyringModel =
new KeyringModel(keyringService, mCryptoModel.getSharedData(), braveWalletService);
mKeyringModel = new KeyringModel(
keyringService, mCryptoModel.getSharedData(), braveWalletService, mCryptoActions);
init();
}
public void resetServices(KeyringService keyringService, BlockchainRegistry blockchainRegistry,
JsonRpcService jsonRpcService, TxService txService, EthTxManagerProxy ethTxManagerProxy,
public void resetServices(Context context, KeyringService keyringService,
BlockchainRegistry blockchainRegistry, JsonRpcService jsonRpcService,
TxService txService, EthTxManagerProxy ethTxManagerProxy,
SolanaTxManagerProxy solanaTxManagerProxy, AssetRatioService assetRatioService,
BraveWalletService braveWalletService) {
mContext = context;
setKeyringService(keyringService);
setBlockchainRegistry(blockchainRegistry);
setJsonRpcService(jsonRpcService);
@@ -63,7 +74,7 @@ public class WalletModel {
setSolanaTxManagerProxy(solanaTxManagerProxy);
setAssetRatioService(assetRatioService);
setBraveWalletService(braveWalletService);
mCryptoModel.resetServices(mTxService, mKeyringService, mBlockchainRegistry,
mCryptoModel.resetServices(mContext, mTxService, mKeyringService, mBlockchainRegistry,
mJsonRpcService, mEthTxManagerProxy, mSolanaTxManagerProxy, mBraveWalletService,
mAssetRatioService);
mDappsModel.resetServices(
@@ -162,4 +173,11 @@ public class WalletModel {
public void setAssetRatioService(AssetRatioService mAssetRatioService) {
this.mAssetRatioService = mAssetRatioService;
}
class CryptoActions implements CryptoModelActions {
@Override
public void updateCoinType() {
mCryptoModel.updateCoinType();
}
}
}
@@ -6,24 +6,20 @@
package org.chromium.chrome.browser.crypto_wallet.activities;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.view.MenuItem;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.app.domain.KeyringModel;
import org.chromium.chrome.browser.crypto_wallet.adapters.WalletCoinAdapter;
import org.chromium.chrome.browser.crypto_wallet.fragments.AccountsFragment;
import org.chromium.chrome.browser.crypto_wallet.fragments.CreateAccountBottomSheetFragment;
import org.chromium.chrome.browser.crypto_wallet.listeners.OnWalletListItemClick;
import org.chromium.chrome.browser.crypto_wallet.model.WalletListItemModel;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -55,34 +51,33 @@ public class AccountSelectorActivity
mRVNetworkSelector.setAdapter(mWalletCoinAdapter);
mWalletCoinAdapter.setOnWalletListItemClick(this);
mWalletCoinAdapter.setOnWalletListItemClick(this);
mKeyringModel.mKeyringInfoLiveData.observe(this, keyringInfo -> {
if (keyringInfo != null) {
mAccountInfos = keyringInfo.accountInfos;
List<WalletListItemModel> walletListItemModelList = new ArrayList<>();
for (AccountInfo accountInfo : mAccountInfos) {
if (!accountInfo.isImported) {
walletListItemModelList.add(
new WalletListItemModel(R.drawable.ic_eth, accountInfo.name,
accountInfo.address, null, null, accountInfo.isImported));
}
mKeyringModel.getAccounts(accountInfos -> {
mAccountInfos = accountInfos;
List<WalletListItemModel> walletListItemModelList = new ArrayList<>();
for (AccountInfo accountInfo : mAccountInfos) {
if (!accountInfo.isImported) {
walletListItemModelList.add(
new WalletListItemModel(R.drawable.ic_eth, accountInfo.name,
accountInfo.address, null, null, accountInfo.isImported));
}
mWalletCoinAdapter.setWalletListItemModelList(walletListItemModelList);
mWalletCoinAdapter.notifyDataSetChanged();
}
mWalletCoinAdapter.setWalletListItemModelList(walletListItemModelList);
mWalletCoinAdapter.notifyDataSetChanged();
mKeyringModel.mSelectedAccount.observe(this, selectedAccountInfo -> {
if (selectedAccountInfo != null) {
mWalletCoinAdapter.updateSelectedNetwork(
selectedAccountInfo.name, selectedAccountInfo.address);
}
});
});
mKeyringModel.mSelectedAccount.observe(this, selectedAccountInfo -> {
if (selectedAccountInfo != null) {
mWalletCoinAdapter.updateSelectedNetwork(
selectedAccountInfo.name, selectedAccountInfo.address);
}
});
MaterialToolbar toolbar = findViewById(R.id.toolbar);
toolbar.setOnMenuItemClickListener(item -> {
Intent intent = new Intent(this, AddAccountActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
BottomSheetDialogFragment sheetDialogFragment = new CreateAccountBottomSheetFragment();
sheetDialogFragment.show(
getSupportFragmentManager(), CreateAccountBottomSheetFragment.TAG);
return true;
});
}
@@ -20,13 +20,18 @@ import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import com.google.android.gms.common.util.ArrayUtils;
import org.chromium.base.Log;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.BraveWalletConstants;
import org.chromium.brave_wallet.mojom.CoinType;
import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.crypto_wallet.KeyringServiceFactory;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import org.chromium.chrome.browser.crypto_wallet.observers.KeyringServiceObserver;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.chrome.browser.init.AsyncInitializationActivity;
@@ -42,6 +47,8 @@ import java.util.List;
import java.util.Map;
public class AddAccountActivity extends BraveWalletBaseActivity {
public static final String ACCOUNT = "account";
private String mAddress;
private String mName;
private boolean mIsUpdate;
@@ -49,6 +56,8 @@ public class AddAccountActivity extends BraveWalletBaseActivity {
private EditText mPrivateKeyControl;
private EditText mAddAccountText;
private static final int FILE_PICKER_REQUEST_CODE = 1;
private CryptoAccountTypeInfo mCryptoAccountTypeInfo;
private WalletModel mWalletModel;
public AddAccountActivity() {
mIsUpdate = false;
@@ -63,10 +72,21 @@ public class AddAccountActivity extends BraveWalletBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(getResources().getString(R.string.add_account));
final Button btnAdd = findViewById(R.id.btn_add);
btnAdd.setEnabled(false);
mAddAccountText = findViewById(R.id.add_account_text);
mPrivateKeyControl = findViewById(R.id.import_account_text);
final Button btnAdd = findViewById(R.id.btn_add);
TextView importBtn = findViewById(R.id.import_btn);
EditText importAccountPasswordText = findViewById(R.id.import_account_password_text);
btnAdd.setEnabled(false);
BraveActivity activity = BraveActivity.getBraveActivity();
assert activity != null;
mWalletModel = activity.getWalletModel();
mCryptoAccountTypeInfo = (CryptoAccountTypeInfo) getIntent().getSerializableExtra(ACCOUNT);
mAddAccountText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {}
@@ -83,106 +103,93 @@ public class AddAccountActivity extends BraveWalletBaseActivity {
}
});
mPrivateKeyControl = findViewById(R.id.import_account_text);
EditText importAccountPasswordText = findViewById(R.id.import_account_password_text);
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mKeyringService != null) {
if (mIsUpdate) {
if (mIsImported) {
mKeyringService.setKeyringImportedAccountName(
BraveWalletConstants.DEFAULT_KEYRING_ID, mAddress,
mAddAccountText.getText().toString(), result -> {
if (result) {
Intent returnIntent = new Intent();
returnIntent.putExtra(Utils.NAME,
mAddAccountText.getText().toString());
setResult(Activity.RESULT_OK, returnIntent);
finish();
} else {
mAddAccountText.setError(
getString(R.string.account_update_failed));
}
});
} else {
mKeyringService.setKeyringDerivedAccountName(
BraveWalletConstants.DEFAULT_KEYRING_ID, mAddress,
mAddAccountText.getText().toString(), result -> {
if (result) {
Intent returnIntent = new Intent();
returnIntent.putExtra(Utils.NAME,
mAddAccountText.getText().toString());
setResult(Activity.RESULT_OK, returnIntent);
finish();
} else {
mAddAccountText.setError(
getString(R.string.account_update_failed));
}
});
}
} else if (!TextUtils.isEmpty(mPrivateKeyControl.getText().toString())) {
if (Utils.isJSONValid(mPrivateKeyControl.getText().toString())) {
mKeyringService.importAccountFromJson(
mAddAccountText.getText().toString(),
importAccountPasswordText.getText().toString(),
mPrivateKeyControl.getText().toString(), (result, address) -> {
if (result) {
setResult(Activity.RESULT_OK);
Utils.clearClipboard(
mPrivateKeyControl.getText().toString(), 0);
Utils.clearClipboard(
importAccountPasswordText.getText().toString(),
0);
finish();
} else {
mAddAccountText.setError(getString(
R.string.wallet_failed_to_import_account));
}
});
} else {
mKeyringService.importAccount(mAddAccountText.getText().toString(),
mPrivateKeyControl.getText().toString().trim(), CoinType.ETH,
(result, address) -> {
if (result) {
setResult(Activity.RESULT_OK);
Utils.clearClipboard(
mPrivateKeyControl.getText().toString(), 0);
finish();
} else {
mAddAccountText.setError(getString(
R.string.wallet_failed_to_import_account));
}
});
}
} else {
mKeyringService.addAccount(
mAddAccountText.getText().toString(), CoinType.ETH, result -> {
btnAdd.setOnClickListener(v -> {
if (mKeyringService != null) {
if (mIsUpdate) {
if (mIsImported) {
mKeyringService.setKeyringImportedAccountName(
BraveWalletConstants.DEFAULT_KEYRING_ID, mAddress,
mAddAccountText.getText().toString(), result -> {
if (result) {
setResult(Activity.RESULT_OK);
Intent returnIntent = new Intent();
returnIntent.putExtra(
Utils.NAME, mAddAccountText.getText().toString());
setResult(Activity.RESULT_OK, returnIntent);
finish();
} else {
mAddAccountText.setError(
getString(R.string.account_name_empty_error));
getString(R.string.account_update_failed));
}
});
} else {
mKeyringService.setKeyringDerivedAccountName(
BraveWalletConstants.DEFAULT_KEYRING_ID, mAddress,
mAddAccountText.getText().toString(), result -> {
if (result) {
Intent returnIntent = new Intent();
returnIntent.putExtra(
Utils.NAME, mAddAccountText.getText().toString());
setResult(Activity.RESULT_OK, returnIntent);
finish();
} else {
mAddAccountText.setError(
getString(R.string.account_update_failed));
}
});
}
} else if (!TextUtils.isEmpty(mPrivateKeyControl.getText().toString())) {
if (Utils.isJSONValid(mPrivateKeyControl.getText().toString())) {
mKeyringService.importAccountFromJson(mAddAccountText.getText().toString(),
importAccountPasswordText.getText().toString(),
mPrivateKeyControl.getText().toString(), (result, address) -> {
if (result) {
setResult(Activity.RESULT_OK);
Utils.clearClipboard(
mPrivateKeyControl.getText().toString(), 0);
Utils.clearClipboard(
importAccountPasswordText.getText().toString(), 0);
finish();
} else {
mAddAccountText.setError(getString(
R.string.wallet_failed_to_import_account));
}
});
} else {
mKeyringService.importAccount(mAddAccountText.getText().toString(),
mPrivateKeyControl.getText().toString().trim(),
mCryptoAccountTypeInfo.getCoinType(), (result, address) -> {
if (result) {
setResult(Activity.RESULT_OK);
Utils.clearClipboard(
mPrivateKeyControl.getText().toString(), 0);
finish();
} else {
mAddAccountText.setError(getString(
R.string.wallet_failed_to_import_account));
}
});
}
} else {
mWalletModel.getKeyringModel().addAccount(mAddAccountText.getText().toString(),
mCryptoAccountTypeInfo.getCoinType(), result -> {
if (result) {
setResult(Activity.RESULT_OK);
finish();
} else {
mAddAccountText.setError(
getString(R.string.account_name_empty_error));
}
});
}
}
});
TextView importBtn = findViewById(R.id.import_btn);
importBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(
chooseFile, getResources().getString(R.string.choose_a_file));
startActivityForResult(chooseFile, FILE_PICKER_REQUEST_CODE);
}
importBtn.setOnClickListener(v -> {
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(
chooseFile, getResources().getString(R.string.choose_a_file));
startActivityForResult(chooseFile, FILE_PICKER_REQUEST_CODE);
});
onInitialLayoutInflationComplete();
@@ -212,19 +219,25 @@ public class AddAccountActivity extends BraveWalletBaseActivity {
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
assert mKeyringService != null;
mKeyringService.getKeyringInfo(BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
if (keyringInfo != null) {
mAddAccountText.setText(getUniqueNextAccountName(keyringInfo.accountInfos, 1));
mWalletModel.getKeyringModel().getAccounts(accountInfos -> {
ArrayList<AccountInfo> accountInfoList = new ArrayList<>();
for (AccountInfo accountInfo : accountInfos) {
if (accountInfo.coin == mCryptoAccountTypeInfo.getCoinType()) {
accountInfoList.add(accountInfo);
}
}
mAddAccountText.setText(getUniqueNextAccountName(
accountInfoList.toArray(new AccountInfo[0]), 1, mCryptoAccountTypeInfo));
});
}
private String getUniqueNextAccountName(AccountInfo[] accountInfos, int number) {
String accountName = getString(
R.string.new_account_prefix, String.valueOf(accountInfos.length + number));
private String getUniqueNextAccountName(
AccountInfo[] accountInfos, int number, CryptoAccountTypeInfo cryptoAccountTypeInfo) {
String accountName = getString(R.string.new_account_prefix, cryptoAccountTypeInfo.getName(),
String.valueOf(accountInfos.length + number));
for (AccountInfo accountInfo : accountInfos) {
if (accountInfo.name.equals(accountName)) {
return getUniqueNextAccountName(accountInfos, number + 1);
return getUniqueNextAccountName(accountInfos, number + 1, cryptoAccountTypeInfo);
}
}
@@ -0,0 +1,93 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.crypto_wallet.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CreateAccountAdapter extends RecyclerView.Adapter<CreateAccountAdapter.ViewHolder> {
private Context mContext;
private final ExecutorService mExecutor;
private final Handler mHandler;
private final LayoutInflater inflater;
private OnCreateAccountClickListener mCreateAccountClickListener;
private List<CryptoAccountTypeInfo> mCryptoAccountTypeInfos;
public CreateAccountAdapter(
Context context, List<CryptoAccountTypeInfo> cryptoAccountTypeInfos) {
mCryptoAccountTypeInfos = cryptoAccountTypeInfos;
this.mContext = context;
inflater = (LayoutInflater.from(context));
mExecutor = Executors.newSingleThreadExecutor();
mHandler = new Handler(Looper.getMainLooper());
}
@Override
public @NonNull ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
View view = inflater.inflate(R.layout.item_create_account, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
final CryptoAccountTypeInfo accountTypeInfo = mCryptoAccountTypeInfos.get(position);
holder.tvTitle.setText(accountTypeInfo.getName());
holder.tvDesc.setText(accountTypeInfo.getDesc());
holder.ivNetworkPicture.setImageResource(accountTypeInfo.getIcon());
holder.itemView.setOnClickListener(v -> {
assert mCreateAccountClickListener != null;
mCreateAccountClickListener.onAccountClick(accountTypeInfo);
});
}
@Override
public int getItemCount() {
return mCryptoAccountTypeInfos.size();
}
public void setOnAccountItemSelected(OnCreateAccountClickListener listener) {
mCreateAccountClickListener = listener;
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivNetworkPicture;
TextView tvTitle;
TextView tvDesc;
ViewHolder(View itemView) {
super(itemView);
ivNetworkPicture = itemView.findViewById(R.id.item_create_account_iv_icon);
tvTitle = itemView.findViewById(R.id.item_create_account_tv_title);
tvDesc = itemView.findViewById(R.id.item_create_account_tv_desc);
}
}
public interface OnCreateAccountClickListener {
void onAccountClick(CryptoAccountTypeInfo cryptoAccountTypeInfo);
}
}
@@ -65,8 +65,7 @@ public class WalletCoinAdapter extends RecyclerView.Adapter<WalletCoinAdapter.Vi
}
@Override
public @NonNull WalletCoinAdapter.ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType) {
public @NonNull ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View walletCoinView = inflater.inflate(R.layout.wallet_coin_list_item, parent, false);
@@ -74,7 +73,7 @@ public class WalletCoinAdapter extends RecyclerView.Adapter<WalletCoinAdapter.Vi
}
@Override
public void onBindViewHolder(@NonNull WalletCoinAdapter.ViewHolder holder, int position) {
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
WalletListItemModel walletListItemModel = walletListItemModelList.get(position);
// When ViewHolder is re-used, it has the obeservers which are fired when
// we modifying checkbox. This may cause unwanted modifying of the model
@@ -166,6 +166,8 @@ public class DAppsWalletController implements ConnectionErrorHandler, KeyringSer
if (isShowingDialog()) {
mDAppsDialog.dismiss();
}
mBraveWalletPanel = null;
mDAppsDialog = null;
cleanUp();
}
@@ -241,6 +243,13 @@ public class DAppsWalletController implements ConnectionErrorHandler, KeyringSer
mBraveWalletPanel.resume();
}
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
if (mBraveWalletPanel != null) {
mBraveWalletPanel.pause();
}
}
};
private boolean shouldShowNotificationAtTop(Context context) {
@@ -20,11 +20,15 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.BraveWalletConstants;
import org.chromium.brave_wallet.mojom.KeyringInfo;
import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.crypto_wallet.activities.AccountDetailActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.AddAccountActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.BraveWalletActivity;
@@ -42,6 +46,8 @@ import java.util.List;
public class AccountsFragment extends Fragment implements OnWalletListItemClick {
private View rootView;
private WalletCoinAdapter walletCoinAdapter;
private WalletModel mWalletModel;
public static AccountsFragment newInstance() {
return new AccountsFragment();
}
@@ -50,6 +56,10 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
BraveActivity activity = BraveActivity.getBraveActivity();
if (activity != null) {
mWalletModel = activity.getWalletModel();
}
}
@Nullable
@@ -66,9 +76,9 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
TextView addAccountBtn = view.findViewById(R.id.add_account_btn);
addAccountBtn.setOnClickListener(v -> {
Intent addAccountActivityIntent = new Intent(getActivity(), AddAccountActivity.class);
addAccountActivityIntent.putExtra(Utils.ISUPDATEACCOUNT, false);
startActivityForResult(addAccountActivityIntent, Utils.ACCOUNT_REQUEST_CODE);
BottomSheetDialogFragment sheetDialogFragment = new CreateAccountBottomSheetFragment();
sheetDialogFragment.show(
getChildFragmentManager(), CreateAccountBottomSheetFragment.TAG);
});
TextView backupBtn = view.findViewById(R.id.accounts_backup);
@@ -88,11 +98,8 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
private void setUpAccountList(View view) {
RecyclerView rvAccounts = view.findViewById(R.id.rv_accounts);
walletCoinAdapter = new WalletCoinAdapter(WalletCoinAdapter.AdapterType.ACCOUNTS_LIST);
KeyringService keyringService = getKeyringService();
if (keyringService != null) {
keyringService.getKeyringInfo(BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
if (keyringInfo != null) {
AccountInfo[] accountInfos = keyringInfo.accountInfos;
mWalletModel.getKeyringModel().mAccountInfos.observe(
getViewLifecycleOwner(), accountInfos -> {
List<WalletListItemModel> walletListItemModelList = new ArrayList<>();
for (AccountInfo accountInfo : accountInfos) {
if (!accountInfo.isImported) {
@@ -108,20 +115,15 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
rvAccounts.setAdapter(walletCoinAdapter);
rvAccounts.setLayoutManager(new LinearLayoutManager(getActivity()));
}
}
});
}
});
}
private void setUpSecondaryAccountList(View view) {
RecyclerView rvSecondaryAccounts = view.findViewById(R.id.rv_secondary_accounts);
WalletCoinAdapter walletCoinAdapter =
new WalletCoinAdapter(WalletCoinAdapter.AdapterType.ACCOUNTS_LIST);
KeyringService keyringService = getKeyringService();
if (keyringService != null) {
keyringService.getKeyringInfo(BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
if (keyringInfo != null) {
AccountInfo[] accountInfos = keyringInfo.accountInfos;
mWalletModel.getKeyringModel().mAccountInfos.observe(
getViewLifecycleOwner(), accountInfos -> {
List<WalletListItemModel> walletListItemModelList = new ArrayList<>();
for (AccountInfo accountInfo : accountInfos) {
if (accountInfo.isImported) {
@@ -138,9 +140,7 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
rvSecondaryAccounts.setLayoutManager(
new LinearLayoutManager(getActivity()));
}
}
});
}
});
}
@Override
@@ -150,7 +150,7 @@ public class AccountsFragment extends Fragment implements OnWalletListItemClick
accountDetailActivityIntent.putExtra(Utils.ADDRESS, walletListItemModel.getSubTitle());
accountDetailActivityIntent.putExtra(
Utils.ISIMPORTED, walletListItemModel.getIsImportedAccount());
startActivityForResult(accountDetailActivityIntent, Utils.ACCOUNT_REQUEST_CODE);
startActivity(accountDetailActivityIntent);
}
@Override
@@ -0,0 +1,78 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.crypto_wallet.fragments;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.crypto_wallet.activities.AddAccountActivity;
import org.chromium.chrome.browser.crypto_wallet.adapters.CreateAccountAdapter;
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import java.util.ArrayList;
import java.util.List;
public class CreateAccountBottomSheetFragment extends BottomSheetDialogFragment
implements CreateAccountAdapter.OnCreateAccountClickListener {
public static final String TAG = "CreateAccountBottomSheetFragment";
private View rootView;
private WalletModel mWalletModel;
private List<CryptoAccountTypeInfo> mSupportedCryptoAccounts;
private RecyclerView mRvAccounts;
private CreateAccountAdapter mCreateAccountAdapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSupportedCryptoAccounts = new ArrayList<>();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_create_account, container, false);
return rootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSupportedCryptoAccounts.clear();
BraveActivity activity = BraveActivity.getBraveActivity();
if (activity != null) {
mWalletModel = activity.getWalletModel();
mSupportedCryptoAccounts =
mWalletModel.getCryptoModel().getSupportedCryptoAccountTypes();
}
mRvAccounts = view.findViewById(R.id.fragment_create_account_rv);
mCreateAccountAdapter =
new CreateAccountAdapter(requireContext(), mSupportedCryptoAccounts);
mRvAccounts.setAdapter(mCreateAccountAdapter);
mCreateAccountAdapter.setOnAccountItemSelected(this);
}
@Override
public void onAccountClick(CryptoAccountTypeInfo cryptoAccountTypeInfo) {
Intent addAccountActivityIntent = new Intent(getActivity(), AddAccountActivity.class);
addAccountActivityIntent.putExtra(AddAccountActivity.ACCOUNT, cryptoAccountTypeInfo);
startActivity(addAccountActivityIntent);
dismiss();
}
}
@@ -19,6 +19,8 @@ import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.chromium.brave_wallet.mojom.AccountInfo;
import org.chromium.brave_wallet.mojom.BraveWalletConstants;
import org.chromium.brave_wallet.mojom.BraveWalletService;
@@ -29,6 +31,7 @@ import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.AddAccountActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.BraveWalletBaseActivity;
import org.chromium.chrome.browser.crypto_wallet.fragments.CreateAccountBottomSheetFragment;
import org.chromium.chrome.browser.crypto_wallet.permission.BraveEthereumPermissionAccountsListAdapter;
import org.chromium.chrome.browser.crypto_wallet.util.AccountsPermissionsHelper;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
@@ -104,9 +107,10 @@ public class ConnectAccountFragment extends BaseDAppsFragment
mbtNewAccount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), AddAccountActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
BottomSheetDialogFragment sheetDialogFragment =
new CreateAccountBottomSheetFragment();
sheetDialogFragment.show(
getChildFragmentManager(), CreateAccountBottomSheetFragment.TAG);
}
});
mRecyclerView = view.findViewById(R.id.accounts_list);
@@ -5,12 +5,10 @@
package org.chromium.chrome.browser.crypto_wallet.fragments.dapps;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -133,7 +131,7 @@ public class EncryptionKeyFragment extends Fragment implements View.OnClickListe
getString(R.string.brave_wallet_provide_encryption_key_description),
Utils.geteTLDHTMLFormatted(
encryptionPublicKeyRequest.originInfo.eTldPlusOne));
mTvMessageDesc.setText(AndroidUtils.formateHTML(formattedeTLD));
mTvMessageDesc.setText(AndroidUtils.formatHTML(formattedeTLD));
}
});
} else if (mActivityType == BraveWalletDAppsActivity.ActivityType.DECRYPT_REQUEST) {
@@ -27,6 +27,7 @@ import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.lifecycle.Observer;
import org.chromium.base.SysUtils;
import org.chromium.brave_wallet.mojom.AccountInfo;
@@ -39,6 +40,7 @@ import org.chromium.brave_wallet.mojom.KeyringService;
import org.chromium.brave_wallet.mojom.NetworkInfo;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.app.domain.WalletModel;
import org.chromium.chrome.browser.crypto_wallet.activities.AccountSelectorActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.BraveWalletDAppsActivity;
import org.chromium.chrome.browser.crypto_wallet.activities.NetworkSelectorActivity;
@@ -77,6 +79,26 @@ public class BraveWalletPanel implements DialogInterface {
private BraveWalletPanelServices mBraveWalletPanelServices;
private ImageView mAccountChangeAnchor;
private View mContainerConstraintLayout;
private WalletModel mWalletModel;
private Observer<AccountInfo> mAccountInfoObserver = accountInfo -> {
if (accountInfo == null) return;
// TODO (pav): remove BraveWalletConstants.DEFAULT_KEYRING_ID
mBraveWalletPanelServices.getKeyringService().getKeyringInfo(
BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
if (keyringInfo != null) {
mAccountInfos = keyringInfo.accountInfos;
}
AccountsPermissionsHelper accountsPermissionsHelper =
new AccountsPermissionsHelper(
mBraveWalletPanelServices.getBraveWalletService(),
mAccountInfos, Utils.getCurrentMojomOrigin());
accountsPermissionsHelper.checkAccounts(() -> {
mAccountsWithPermissions =
accountsPermissionsHelper.getAccountsWithPermissions();
updateAccountInfo(accountInfo.address);
});
});
};
public interface BraveWalletPanelServices {
AssetRatioService getAssetRatioService();
@@ -118,6 +140,10 @@ public class BraveWalletPanel implements DialogInterface {
dismiss();
}
});
BraveActivity activity = BraveActivity.getBraveActivity();
if (activity != null) {
mWalletModel = activity.getWalletModel();
}
setUpViews();
}
@@ -196,6 +222,7 @@ public class BraveWalletPanel implements DialogInterface {
@Override
public void dismiss() {
cleanUpObservers();
mPopupWindow.dismiss();
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss(this);
@@ -203,12 +230,17 @@ public class BraveWalletPanel implements DialogInterface {
}
public void resume() {
setUpObservers();
if (isShowing()) {
updateState();
updateStatus();
// updateStatus();
}
}
public void pause() {
cleanUpObservers();
}
public boolean isShowing() {
return mPopupWindow != null && mPopupWindow.isShowing();
}
@@ -224,48 +256,15 @@ public class BraveWalletPanel implements DialogInterface {
});
}
private void updateStatus() {
mBraveWalletPanelServices.getKeyringService().getKeyringInfo(
BraveWalletConstants.DEFAULT_KEYRING_ID, keyringInfo -> {
if (keyringInfo != null) {
mAccountInfos = keyringInfo.accountInfos;
}
AccountsPermissionsHelper accountsPermissionsHelper =
new AccountsPermissionsHelper(
mBraveWalletPanelServices.getBraveWalletService(),
mAccountInfos, Utils.getCurrentMojomOrigin());
accountsPermissionsHelper.checkAccounts(() -> {
mAccountsWithPermissions =
accountsPermissionsHelper.getAccountsWithPermissions();
updateAccount();
});
});
private void setUpObservers() {
cleanUpObservers();
mWalletModel.getKeyringModel().getSelectedAccountOrAccountPerOrigin().observeForever(
mAccountInfoObserver);
}
private void updateAccount() {
mBraveWalletPanelServices.getKeyringService().getSelectedAccount(CoinType.ETH, address -> {
String selectedAccount = "";
if (address != null && !address.isEmpty()) {
selectedAccount = address;
updateAccountInfo(selectedAccount);
} else {
if (!mAccountsWithPermissions.isEmpty()) {
selectedAccount = mAccountsWithPermissions.iterator().next().address;
} else if (mAccountInfos.length > 0) {
selectedAccount = mAccountInfos[0].address;
}
setSelectedAccount(selectedAccount);
}
});
}
private void setSelectedAccount(String selectedAccount) {
mBraveWalletPanelServices.getKeyringService().setSelectedAccount(
selectedAccount, CoinType.ETH, success -> {
if (success) {
updateAccountInfo(selectedAccount);
}
});
private void cleanUpObservers() {
mWalletModel.getKeyringModel().getSelectedAccountOrAccountPerOrigin().removeObserver(
mAccountInfoObserver);
}
private void updateAccountInfo(String selectedAccount) {
@@ -387,6 +386,7 @@ public class BraveWalletPanel implements DialogInterface {
}
});
updateState();
updateStatus();
setUpObservers();
// updateStatus();
}
}
@@ -0,0 +1,59 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.crypto_wallet.model;
import androidx.annotation.IntegerRes;
import org.chromium.brave_wallet.mojom.CoinType;
import java.io.Serializable;
public class CryptoAccountTypeInfo implements Serializable {
private String desc;
private String name;
private int coinType;
private @IntegerRes int icon;
public CryptoAccountTypeInfo(
String desc, String name, @CoinType.EnumType int coinType, int icon) {
this.desc = desc;
this.name = name;
this.coinType = coinType;
this.icon = icon;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public @CoinType.EnumType int getCoinType() {
return coinType;
}
public void setCoinType(@CoinType.EnumType int coinType) {
this.coinType = coinType;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
}
@@ -36,7 +36,7 @@ public class AndroidUtils {
}
}
public static Spanned formateHTML(String html) {
public static Spanned formatHTML(String html) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
} else {
@@ -1600,7 +1600,7 @@ public class Utils {
Context context, @StringRes int stringRes, View.OnClickListener onClickListener) {
String htmlString =
String.format(context.getResources().getString(stringRes), "<a href=\"\">", "</a>");
Spannable spannable = new SpannableString(AndroidUtils.formateHTML(htmlString));
Spannable spannable = new SpannableString(AndroidUtils.formatHTML(htmlString));
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
for (URLSpan urlSpan : spans) {
NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan(context,
@@ -1690,7 +1690,7 @@ public class Utils {
public static Spanned geteTLD(GURL url, String etldPlusOne) {
String formattedeTLD = geteTLDHTMLFormatted(url, etldPlusOne);
return AndroidUtils.formateHTML(formattedeTLD);
return AndroidUtils.formatHTML(formattedeTLD);
}
private static String geteTLDHTMLFormatted(GURL url, String etldPlusOne) {
@@ -0,0 +1,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="200dp"
android:height="200dp"
android:viewportWidth="800"
android:viewportHeight="800">
<path
android:fillColor="#FF000000"
android:pathData="M400,400m-369.5,0a369.5,369.5 0,1 1,739 0a369.5,369.5 0,1 1,-739 0"/>
<group>
<clip-path
android:pathData="M178.3,206.01h443.4v387.97h-443.4z"/>
<path
android:pathData="M258.52,501.85a14.86,14.86 0,0 1,5 -3.59,15.13 15.13,0 0,1 6,-1.27l338.61,0.28a7.44,7.44 0,0 1,5.49 12.46l-72.11,79.4a14.86,14.86 0,0 1,-11 4.86l-338.6,-0.28a7.45,7.45 0,0 1,-5.49 -12.46ZM613.59,435.76a7.44,7.44 0,0 1,-5.49 12.46l-338.6,0.28a14.86,14.86 0,0 1,-11 -4.86L186.41,364.2a7.47,7.47 0,0 1,-1.84 -3.82,7.43 7.43,0 0,1 3.27,-7.43 7.52,7.52 0,0 1,4.06 -1.22l338.61,-0.27a14.81,14.81 0,0 1,11 4.86ZM258.52,210.87a14.81,14.81 0,0 1,11 -4.86l338.61,0.28a7.44,7.44 0,0 1,6.8 4.44,7.42 7.42,0 0,1 -1.31,8l-72.11,79.4a14.86,14.86 0,0 1,-11 4.86l-338.6,-0.28a7.42,7.42 0,0 1,-6.8 -4.45,7.46 7.46,0 0,1 1.31,-8Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="197.56"
android:startY="602.44"
android:endX="602.44"
android:endY="197.56"
android:type="linear">
<item android:offset="0" android:color="#FF9945FF"/>
<item android:offset="0.2" android:color="#FF7962E7"/>
<item android:offset="1" android:color="#FF00D18C"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>
@@ -87,7 +87,7 @@
android:id = "@+id/add_account_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_account"
android:text="@string/add_import_account"
android:textColor="@color/wallet_text_color"
android:background="@drawable/rounded_white_holo_bg"
android:gravity="center"
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment_create_account_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:background="@color/wallet_bg"
android:layout_marginTop="4dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/item_create_account" />
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:paddingEnd="8dp"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal">
<ImageView
android:id="@+id/item_create_account_iv_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginHorizontal="8dp"
android:layout_gravity="center"
android:contentDescription="@null"
android:background="@drawable/eth"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight=".5"
android:orientation="vertical">
<TextView
android:id="@+id/item_create_account_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginEnd="8dp"
android:textColor="@color/wallet_text_color"
android:textSize="14sp"
android:textStyle="bold"
tools:text="Eth" />
<TextView
android:id="@+id/item_create_account_tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
tools:text="DescDescDescDescDescDescDescDescDescDescDescDesc"
android:textColor="@color/wallet_secondary_layout_text_color"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>