Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add all network selector support #17725

Merged
merged 3 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class CryptoModel {
private TxService mTxService;
Expand Down Expand Up @@ -387,6 +388,14 @@ public List<CryptoAccountTypeInfo> getSupportedCryptoAccountTypes() {
return CryptoModel.this.getSupportedCryptoAccountTypes();
}

@Override
public List<Integer> getSupportedCryptoCoins() {
return getSupportedCryptoAccountTypes()
.stream()
.map(CryptoAccountTypeInfo::getCoinType)
.collect(Collectors.toList());
}

@Override
public LiveData<List<AccountInfo>> getAccounts() {
return mAccountInfosFromKeyRingModel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/* Copyright (c) 2023 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 https://mozilla.org/MPL/2.0/. */

package org.chromium.chrome.browser.app.domain;

import android.content.Context;
Expand All @@ -16,5 +21,6 @@ public interface CryptoSharedData {
LiveData<Integer> getCoinTypeLd();
String[] getEnabledKeyrings();
List<CryptoAccountTypeInfo> getSupportedCryptoAccountTypes();
List<Integer> getSupportedCryptoCoins();
LiveData<List<AccountInfo>> getAccounts();
}
104 changes: 86 additions & 18 deletions android/java/org/chromium/chrome/browser/app/domain/NetworkModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import android.text.TextUtils;
import android.util.Pair;

import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
Expand All @@ -24,6 +28,7 @@
import org.chromium.chrome.browser.crypto_wallet.model.CryptoAccountTypeInfo;
import org.chromium.chrome.browser.crypto_wallet.util.JavaUtils;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkResponsesCollector;
import org.chromium.chrome.browser.crypto_wallet.util.NetworkUtils;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
import org.chromium.chrome.browser.crypto_wallet.util.WalletConstants;
import org.chromium.chrome.browser.util.Triple;
Expand All @@ -33,7 +38,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class NetworkModel implements JsonRpcServiceObserver {
private JsonRpcService mJsonRpcService;
Expand All @@ -52,7 +61,7 @@ public class NetworkModel implements JsonRpcServiceObserver {
private final MediatorLiveData<String[]> _mCustomNetworkIds;
private final MediatorLiveData<List<NetworkInfo>> _mPrimaryNetworks;
private final MediatorLiveData<List<NetworkInfo>> _mSecondaryNetworks;
private NetworkSelectorModel mNetworkSelectorModel;
private Map<String, NetworkSelectorModel> mNetworkSelectorMap;
public final LiveData<String[]> mCustomNetworkIds;
public LiveData<NetworkInfo> mNeedToCreateAccountForNetwork;
public final LiveData<Triple<String, NetworkInfo, List<NetworkInfo>>> mChainNetworkAllNetwork;
Expand Down Expand Up @@ -93,7 +102,7 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
_mSecondaryNetworks = new MediatorLiveData<>();
mSecondaryNetworks = _mSecondaryNetworks;
jsonRpcService.addObserver(this);
mNetworkSelectorModel = new NetworkSelectorModel(this, mContext);
mNetworkSelectorMap = new HashMap<>();
_mPairChainAndNetwork.setValue(Pair.create("", Collections.emptyList()));
_mPairChainAndNetwork.addSource(_mChainId, chainId -> {
_mPairChainAndNetwork.setValue(
Expand All @@ -107,8 +116,7 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
List<NetworkInfo> cryptoNetworks = chainIdAndInfosPair.second;
if (chainId == null || cryptoNetworks == null) return;
for (NetworkInfo networkInfo : cryptoNetworks) {
if (networkInfo.chainId.equals(chainId)
&& sharedData.getCoinType() == networkInfo.coin) {
if (networkInfo.chainId.equals(chainId)) {
_mDefaultNetwork.postValue(networkInfo);
break;
}
Expand All @@ -133,11 +141,19 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
});

_mChainNetworkAllNetwork.addSource(_mDefaultNetwork, networkInfo -> {
NetworkInfo currNetwork = null;
if (_mChainNetworkAllNetwork.getValue() != null) {
currNetwork = _mChainNetworkAllNetwork.getValue().second;
}
if (currNetwork != null && networkInfo != null
&& NetworkUtils.Filters.isSameNetwork(currNetwork, networkInfo)) {
return;
}
_mChainNetworkAllNetwork.postValue(
Triple.create(networkInfo.chainId, networkInfo, _mCryptoNetworks.getValue()));
});
_mChainNetworkAllNetwork.addSource(_mCryptoNetworks, networkInfos -> {
String chainId = _mChainId.getValue();
String chainId = null;
NetworkInfo networkInfo = _mDefaultNetwork.getValue();
if (networkInfo != null) {
chainId = networkInfo.chainId;
Expand Down Expand Up @@ -174,12 +190,43 @@ public NetworkModel(JsonRpcService jsonRpcService, CryptoSharedData sharedData,
* @return mNetworkSelectorModel object in DEFAULT_WALLET_NETWORK mode
*/
public NetworkSelectorModel openNetworkSelectorModel() {
return openNetworkSelectorModel(NetworkSelectorModel.Mode.DEFAULT_WALLET_NETWORK);
return new NetworkSelectorModel(this, mContext);
}

public NetworkSelectorModel openNetworkSelectorModel(NetworkSelectorModel.Mode mode) {
mNetworkSelectorModel.updateSelectorMode(mode);
return mNetworkSelectorModel;
/**
* Create a network model to handle either default or local state (onscreen e.g. {@link
* org.chromium.chrome.browser.crypto_wallet.fragments.PortfolioFragment}). Local network
* selection can be used by many views so make sure to use the same key which acts as a contract
* between the view and the selection activity.
* @param key acts as a binding key between caller and selection activity.
* @param mode to handle network selection event globally or locally.
* @param lifecycle to auto remove network-selection objects.
* @return NetworkSelectorModel object.
*/
public NetworkSelectorModel openNetworkSelectorModel(
String key, NetworkSelectorModel.Mode mode, Lifecycle lifecycle) {
NetworkSelectorModel networkSelectorModel;
if (key == null) {
return new NetworkSelectorModel(mode, this, mContext);
} else if (mNetworkSelectorMap.containsKey(key)) {
// Use existing NetworkSelector object to show the previously selected network
networkSelectorModel = mNetworkSelectorMap.get(key);
if (networkSelectorModel != null && mode != networkSelectorModel.getMode()) {
networkSelectorModel.updateSelectorMode(mode);
}
} else {
networkSelectorModel = new NetworkSelectorModel(mode, this, mContext);
mNetworkSelectorMap.put(key, networkSelectorModel);
}
if (lifecycle != null) {
lifecycle.addObserver(new DefaultLifecycleObserver() {
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
mNetworkSelectorMap.remove(key);
}
});
}
return networkSelectorModel;
}

public void setAccountInfosFromKeyRingModel(
Expand Down Expand Up @@ -214,22 +261,27 @@ public void refreshNetworks() {
init();
}

static void getAllNetworks(JsonRpcService jsonRpcService, List<Integer> supportedCoins,
Callbacks.Callback1<Set<NetworkInfo>> callback) {
if (jsonRpcService == null) {
callback.call(Collections.emptySet());
return;
}

NetworkResponsesCollector networkResponsesCollector =
new NetworkResponsesCollector(jsonRpcService, supportedCoins);
networkResponsesCollector.getNetworks(networkInfos -> { callback.call(networkInfos); });
}

public void init() {
synchronized (mLock) {
if (mJsonRpcService == null) {
return;
}

List<Integer> coins = new ArrayList<>();
for (CryptoAccountTypeInfo cryptoAccountTypeInfo :
mSharedData.getSupportedCryptoAccountTypes()) {
coins.add(cryptoAccountTypeInfo.getCoinType());
}
NetworkResponsesCollector networkResponsesCollector =
new NetworkResponsesCollector(mJsonRpcService, coins);
networkResponsesCollector.getNetworks(networkInfos -> {
getAllNetworks(mJsonRpcService, mSharedData.getSupportedCryptoCoins(), allNetworks -> {
_mCryptoNetworks.postValue(
stripDebugNetwork(mContext, new ArrayList<>(networkInfos)));
stripDebugNetwork(mContext, new ArrayList<>(allNetworks)));
});
}
}
Expand All @@ -252,6 +304,11 @@ public void setNetworkWithAccountCheck(
}
}

public void setNetworkWithAccountCheck(String chainId, Callbacks.Callback1<Boolean> callback) {
NetworkInfo networkToBeSetAsSelected = getNetwork(chainId);
setNetworkWithAccountCheck(networkToBeSetAsSelected, callback);
}

public void setNetwork(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
mJsonRpcService.setNetwork(
Expand Down Expand Up @@ -284,6 +341,17 @@ public List<NetworkInfo> stripNoBuySwapNetworks(
return networkInfosFiltered;
}

public NetworkInfo getNetwork(String chainId) {
if (TextUtils.isEmpty(chainId)) return null;
List<NetworkInfo> cryptoNws = JavaUtils.safeVal(_mCryptoNetworks.getValue());
for (NetworkInfo info : cryptoNws) {
if (info.chainId.equals(chainId)) {
return info;
}
}
return null;
}

private List<NetworkInfo> stripDebugNetwork(Context context, List<NetworkInfo> networkInfos) {
if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
return networkInfos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,22 @@
public class NetworkSelectorModel {
private final Context mContext;
private final NetworkModel mNetworkModel;
private final MutableLiveData<NetworkInfo> _mLocalSelectedNetwork;
private final MutableLiveData<NetworkInfo> _mSelectedNetwork;
private Mode mMode;
public LiveData<List<NetworkInfoPresenter>> mPrimaryNetworks;
public LiveData<List<NetworkInfoPresenter>> mSecondaryNetworks;
public final LiveData<NetworkInfo> mSelectedNetwork;
private final LiveData<NetworkInfo> mSelectedNetwork;
private String mSelectedChainId;

public NetworkSelectorModel(Mode mode, NetworkModel networkModel, Context context) {
mMode = mode;
if (mMode == null) {
mMode = Mode.LOCAL_NETWORK_FILTER;
mMode = Mode.DEFAULT_WALLET_NETWORK;
}
mNetworkModel = networkModel;
mContext = context;
_mLocalSelectedNetwork = new MutableLiveData<>();
mSelectedNetwork = _mLocalSelectedNetwork;
_mSelectedNetwork = new MutableLiveData<>();
mSelectedNetwork = _mSelectedNetwork;
init();
}

Expand All @@ -54,9 +55,11 @@ public NetworkSelectorModel(NetworkModel networkModel, Context context) {

public void init() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
_mLocalSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
_mSelectedNetwork.postValue(mNetworkModel.mDefaultNetwork.getValue());
} else if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
if (mSelectedChainId == null) {
_mSelectedNetwork.postValue(NetworkUtils.getAllNetworkOption(mContext));
}
}
mPrimaryNetworks = Transformations.map(mNetworkModel.mPrimaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
Expand All @@ -69,13 +72,15 @@ public void init() {
list.add(new NetworkInfoPresenter(
networkInfo, true, mNetworkModel.getSubTestNetworks(networkInfo)));
}
updateLocalNetwork(networkInfos, mSelectedChainId);
return list;
});
mSecondaryNetworks = Transformations.map(mNetworkModel.mSecondaryNetworks, networkInfos -> {
List<NetworkInfoPresenter> list = new ArrayList<>();
for (NetworkInfo networkInfo : networkInfos) {
list.add(new NetworkInfoPresenter(networkInfo, false, Collections.emptyList()));
}
updateLocalNetwork(networkInfos, mSelectedChainId);
return list;
});
}
Expand All @@ -93,23 +98,46 @@ public void updateSelectorMode(Mode mode) {

public void setNetworkWithAccountCheck(
NetworkInfo networkToBeSetAsSelected, Callbacks.Callback1<Boolean> callback) {
boolean hasAccountOfNetworkType =
mNetworkModel.hasAccountOfNetworkType(networkToBeSetAsSelected);
if (!hasAccountOfNetworkType && mMode == Mode.DEFAULT_WALLET_NETWORK) {
// Delegate to network model to handle account creation flow
mNetworkModel.setNetworkWithAccountCheck(networkToBeSetAsSelected, isSet -> {
callback.call(isSet);
if (isSet) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
}
});
return;
// Default/Global wallet network does not support "All Networks"
if (!networkToBeSetAsSelected.chainId.equals(
NetworkUtils.getAllNetworkOption(mContext).chainId)) {
boolean hasAccountOfNetworkType =
mNetworkModel.hasAccountOfNetworkType(networkToBeSetAsSelected);
if (!hasAccountOfNetworkType || mMode == Mode.DEFAULT_WALLET_NETWORK) {
// Delegate to network model to handle account creation flow if required
mNetworkModel.setNetworkWithAccountCheck(networkToBeSetAsSelected, isSet -> {
callback.call(isSet);
if (isSet) {
_mSelectedNetwork.postValue(networkToBeSetAsSelected);
}
});
return;
}
}
if (mMode == Mode.LOCAL_NETWORK_FILTER) {
_mLocalSelectedNetwork.postValue(networkToBeSetAsSelected);
_mSelectedNetwork.postValue(networkToBeSetAsSelected);
callback.call(true);
}
}

public LiveData<NetworkInfo> getSelectedNetwork() {
if (mMode == Mode.DEFAULT_WALLET_NETWORK) {
return mNetworkModel.mDefaultNetwork;
} else {
return mSelectedNetwork;
}
}

public Mode getMode() {
return mMode;
}

private void updateLocalNetwork(List<NetworkInfo> networkInfos, String chainId) {
NetworkInfo networkInfo = NetworkUtils.findNetwork(networkInfos, chainId);
if (networkInfo != null) {
_mSelectedNetwork.postValue(networkInfo);
}
}

public enum Mode { DEFAULT_WALLET_NETWORK, LOCAL_NETWORK_FILTER }
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
import org.chromium.chrome.browser.crypto_wallet.model.WalletListItemModel;
import org.chromium.chrome.browser.crypto_wallet.observers.ApprovedTxObserver;
import org.chromium.chrome.browser.crypto_wallet.util.AddressUtils;
import org.chromium.chrome.browser.crypto_wallet.util.AssetUtils;
import org.chromium.chrome.browser.crypto_wallet.util.JavaUtils;
import org.chromium.chrome.browser.crypto_wallet.util.TokenUtils;
import org.chromium.chrome.browser.crypto_wallet.util.Utils;
Expand Down Expand Up @@ -136,7 +135,7 @@ public enum ActivityType {
SWAP(2);

private int value;
private static Map map = new HashMap<>();
private static final Map<Integer, ActivityType> map = new HashMap<>();

private ActivityType(int value) {
this.value = value;
Expand All @@ -149,7 +148,7 @@ private ActivityType(int value) {
}

public static ActivityType valueOf(int activityType) {
return (ActivityType) map.get(activityType);
return map.get(activityType);
}

public int getValue() {
Expand Down
Loading