- Fix for WalletConnect V2 Foreground Service (#3367)

pull/3371/head
James Brown 7 months ago committed by GitHub
parent 85112001a2
commit 6f15a6007a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      app/src/main/java/com/alphawallet/app/C.java
  2. 21
      app/src/main/java/com/alphawallet/app/interact/WalletConnectInteract.java
  3. 44
      app/src/main/java/com/alphawallet/app/service/WalletConnectV2Service.java
  4. 16
      app/src/main/java/com/alphawallet/app/ui/HomeActivity.java
  5. 4
      app/src/main/java/com/alphawallet/app/ui/WalletFragment.java
  6. 9
      app/src/main/java/com/alphawallet/app/ui/widget/adapter/TokensAdapter.java
  7. 14
      app/src/main/java/com/alphawallet/app/util/Utils.java
  8. 2
      app/src/main/java/com/alphawallet/app/viewmodel/TokenFunctionViewModel.java
  9. 108
      app/src/main/java/com/alphawallet/app/walletconnect/AWWalletConnectClient.java
  10. 5
      app/src/main/java/com/alphawallet/app/widget/TokenIcon.java

@ -211,6 +211,7 @@ public abstract class C {
public static final String APP_FOREGROUND_STATE = "com.alphawallet.APP_FOREGROUND_STATE";
public static final String EXTRA_APP_FOREGROUND = "com.alphawallet.IS_FOREGORUND";
public static final String QRCODE_SCAN = "com.alphawallet.QRSCAN";
public static final String AWALLET_CODE = "com.alphawallet.AWALLET";
public static final String SIGNAL_NFT_SYNC = "com.alphawallet.SYNC_NFT";
public static final String SYNC_STATUS = "com.alphawallet.SYNC_STATUS";
@ -278,6 +279,7 @@ public abstract class C {
public static final String DAPP_SUFFIX_RECEIVE = "receive";
public static final String DAPP_PREFIX_MAPS = "maps.google.com/maps?daddr=";
public static final String DAPP_PREFIX_WALLETCONNECT = "wc";
public static final String DAPP_PREFIX_AWALLET = "awallet";
public static final String ENS_SCAN_BLOCK = "ens_check_block";
public static final String ENS_HISTORY = "ensHistory";

@ -2,7 +2,6 @@ package com.alphawallet.app.interact;
import com.alphawallet.app.entity.walletconnect.WalletConnectSessionItem;
import com.alphawallet.app.entity.walletconnect.WalletConnectV2SessionItem;
import com.alphawallet.app.service.RealmManager;
import com.walletconnect.web3.wallet.client.Wallet;
import com.walletconnect.web3.wallet.client.Web3Wallet;
@ -15,12 +14,10 @@ import timber.log.Timber;
public class WalletConnectInteract
{
private final RealmManager realmManager;
@Inject
public WalletConnectInteract(RealmManager realmManager)
public WalletConnectInteract()
{
this.realmManager = realmManager;
}
public int getSessionsCount()
@ -30,8 +27,7 @@ public class WalletConnectInteract
public List<WalletConnectSessionItem> getSessions()
{
List<WalletConnectSessionItem> result = new ArrayList<>();
result.addAll(getWalletConnectV2SessionItems());
List<WalletConnectSessionItem> result = new ArrayList<>(getWalletConnectV2SessionItems());
//now sort for active/newness
result.sort((l, r) -> Long.compare(r.expiryTime, l.expiryTime));
@ -39,6 +35,17 @@ public class WalletConnectInteract
return result;
}
public void fetchSessions(SessionFetchCallback sessionFetchCallback)
{
fetch(sessionFetchCallback);
}
private void fetch(SessionFetchCallback sessionFetchCallback)
{
List<WalletConnectSessionItem> result = new ArrayList<>(getWalletConnectV2SessionItems());
sessionFetchCallback.onFetched(result);
}
private List<WalletConnectSessionItem> getWalletConnectV2SessionItems()
{
List<WalletConnectSessionItem> result = new ArrayList<>();

@ -5,7 +5,6 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
@ -21,6 +20,9 @@ import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class WalletConnectV2Service extends Service
{
private static final String TAG = WalletConnectV2Service.class.getName();
final String CHANNEL_ID = "WalletConnectV2Service";
@Override
public IBinder onBind(Intent intent)
{
@ -32,32 +34,38 @@ public class WalletConnectV2Service extends Service
public void onCreate()
{
super.onCreate();
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"WalletConnect V2",
NotificationManager.IMPORTANCE_DEFAULT);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
private Notification createNotification()
{
Intent notificationIntent = new Intent(this, WalletConnectNotificationActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
Intent intent = new Intent(getApplicationContext(), WalletConnectNotificationActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_logo)
.setOnlyAlertOnce(true)
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.notify_wallet_connect_title))
.setContentText(getString(R.string.notify_wallet_connect_content))
.setSmallIcon(R.drawable.ic_logo)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
notificationManager.notify(1, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
@RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChannel()
{
return super.onStartCommand(intent, flags, startId);
CharSequence name = getString(R.string.notify_wallet_connect_title);
String description = getString(R.string.notify_wallet_connect_content);
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Notification notification = createNotification();
startForeground(1, notification);
return START_STICKY;
}
@Override

@ -319,7 +319,7 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
if (data != null)
{
checkIntents(data.toString(), intent);
handleDeeplink(data.toString(), intent);
}
Intent i = new Intent(this, PriceAlertsService.class);
@ -453,6 +453,13 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
hideDialog();
qrCodeScanner.launch(options);
});
getSupportFragmentManager()
.setFragmentResultListener(C.AWALLET_CODE, this, (requestKey, b) ->
{
String code = b.getString(C.AWALLET_CODE);
handleDeeplink(code, null);
});
}
//TODO: Implement all QR scan using this method
@ -476,7 +483,7 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
if (data != null)
{
checkIntents(data.toString(), startIntent);
handleDeeplink(data.toString(), startIntent);
}
}
@ -603,7 +610,7 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
int oldPage = savedInstanceState.getInt(STORED_PAGE);
@ -1095,9 +1102,8 @@ public class HomeActivity extends BaseNavigationActivity implements View.OnClick
inset.show(WindowInsetsCompat.Type.statusBars() | WindowInsetsCompat.Type.navigationBars());
}
private void checkIntents(String importData, Intent startIntent)
private void handleDeeplink(String importData, Intent startIntent)
{
//decode deeplink and handle
DeepLinkRequest request = DeepLinkService.parseIntent(importData, startIntent);
switch (request.type)
{

@ -118,6 +118,7 @@ public class WalletFragment extends BaseFragment implements
private ActivityResultLauncher<Intent> handleBackupClick;
private ActivityResultLauncher<Intent> tokenManagementLauncher;
private boolean completed = false;
private boolean hasWCSession = false;
@Inject
AWWalletConnectClient awWalletConnectClient;
@ -270,6 +271,7 @@ public class WalletFragment extends BaseFragment implements
viewModel.removeDisplayTokens().observe(getViewLifecycleOwner(), this::removeTokens);
viewModel.getTokensService().startWalletSync(this);
viewModel.activeWalletConnectSessions().observe(getViewLifecycleOwner(), walletConnectSessionItems -> {
hasWCSession = !walletConnectSessionItems.isEmpty();
adapter.showActiveWalletConnectSessions(walletConnectSessionItems);
});
}
@ -828,7 +830,7 @@ public class WalletFragment extends BaseFragment implements
@Override
public boolean hasWCSession()
{
return awWalletConnectClient != null && awWalletConnectClient.hasWalletConnectSessions();
return hasWCSession || (awWalletConnectClient != null && awWalletConnectClient.hasWalletConnectSessions());
}
@Override

@ -623,14 +623,7 @@ public class TokensAdapter extends RecyclerView.Adapter<BinderViewHolder>
public void showActiveWalletConnectSessions(List<WalletConnectSessionItem> sessions)
{
if (sessions.isEmpty())
{
removeItem(WalletConnectSessionHolder.VIEW_TYPE);
}
else
{
items.add(new WalletConnectSessionSortedItem(sessions, 2));
}
checkWalletConnect();
}
public void removeItem(int viewType)

@ -73,7 +73,6 @@ import java.net.URLDecoder;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -81,7 +80,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -115,7 +113,7 @@ public class Utils
public static String formatUrl(String url)
{
if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url))
if (URLUtil.isHttpsUrl(url) || URLUtil.isHttpUrl(url) || isWalletPrefix(url))
{
return url;
}
@ -132,6 +130,16 @@ public class Utils
}
}
public static boolean isWalletPrefix(String url)
{
return url.startsWith(C.DAPP_PREFIX_TELEPHONE) ||
url.startsWith(C.DAPP_PREFIX_MAILTO) ||
url.startsWith(C.DAPP_PREFIX_ALPHAWALLET) ||
url.startsWith(C.DAPP_PREFIX_MAPS) ||
url.startsWith(C.DAPP_PREFIX_WALLETCONNECT) ||
url.startsWith(C.DAPP_PREFIX_AWALLET);
}
public static boolean isValidUrl(String url)
{
if (TextUtils.isEmpty(url)) return false;

@ -589,7 +589,7 @@ public class TokenFunctionViewModel extends BaseViewModel implements Transaction
public void checkForNewScript(Token token)
{
if (token == null) return;
//check server for new tokenscript
//check server for new TokenScript
scriptUpdate = assetDefinitionService.checkServerForScript(token, scriptUpdateInProgress)
.observeOn(Schedulers.io())
.subscribeOn(Schedulers.single())

@ -17,6 +17,7 @@ import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.MutableLiveData;
import com.alphawallet.app.App;
@ -83,7 +84,7 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
private ActionSheetCallback actionSheetCallback;
private boolean hasConnection;
private Application application;
private PreferenceRepositoryType preferenceRepository;
private final PreferenceRepositoryType preferenceRepository;
public AWWalletConnectClient(Context context, WalletConnectInteract walletConnectInteract, PreferenceRepositoryType preferenceRepository, GasService gasService)
{
@ -94,23 +95,9 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
hasConnection = false;
}
/*public void onSessionDelete(@NonNull Model.SessionDelete deletedSession)
public void onSessionDelete(@NonNull Model.SessionDelete deletedSession)
{
updateNotification();
}*/
public void onSessionProposal(@NonNull Model.SessionProposal sessionProposal)
{
WalletConnectV2SessionItem sessionItem = WalletConnectV2SessionItem.from(sessionProposal);
if (!validChainId(sessionItem.chains))
{
return;
}
AWWalletConnectClient.sessionProposal = sessionProposal;
Intent intent = new Intent(context, WalletConnectV2Activity.class);
intent.putExtra("session", sessionItem);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
updateNotification(null);
}
public boolean hasWalletConnectSessions()
@ -135,36 +122,6 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
return true;
}
public void onSessionRequest(@NonNull Model.SessionRequest sessionRequest)
{
String checkMethod;
String method = sessionRequest.getRequest().getMethod();
if (method.startsWith("eth_signTypedData"))
{
checkMethod = "eth_signTypedData";
}
else
{
checkMethod = method;
}
if (!WCMethodChecker.includes(checkMethod))
{
reject(sessionRequest);
return;
}
Model.Session settledSession = getSession(sessionRequest.getTopic());
Activity topActivity = App.getInstance().getTopActivity();
if (topActivity != null)
{
WalletConnectV2SessionRequestHandler handler = new WalletConnectV2SessionRequestHandler(sessionRequest, settledSession, topActivity, this);
handler.handle(method, actionSheetCallback);
requestHandlers.append(sessionRequest.getRequest().getId(), handler);
}
}
private Session getSession(String topic)
{
List<Session> listOfSettledSessions;
@ -223,7 +180,7 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
Params.SessionApprove approve = new Params.SessionApprove(proposerPublicKey, buildNamespaces(sessionProposal, selectedAccounts), sessionProposal.getRelayProtocol());
Web3Wallet.INSTANCE.approveSession(approve, sessionApprove -> {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
//updateNotification();
updateNotification(sessionProposal);
callback.onSessionProposalApproved();
}, 500);
return null;
@ -295,18 +252,35 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
return sessionItemMutableLiveData;
}
private void updateService(Context context, List<WalletConnectSessionItem> walletConnectSessionItems)
public void updateNotification(Model.SessionProposal sessionProposal)
{
walletConnectInteract.fetchSessions(items -> {
if (sessionProposal != null && items.isEmpty())
{
items.add(WalletConnectV2SessionItem.from(sessionProposal));
}
updateService(items);
sessionItemMutableLiveData.postValue(items);
});
}
private void updateService(List<WalletConnectSessionItem> items)
{
try
{
if (walletConnectSessionItems.isEmpty())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
if (items.isEmpty())
{
context.stopService(new Intent(context, WalletConnectV2Service.class));
//now signal
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
else
{
Intent service = new Intent(context, WalletConnectV2Service.class);
context.startForegroundService(service);
Intent serviceIntent = new Intent(context, WalletConnectV2Service.class);
ContextCompat.startForegroundService(context, serviceIntent);
}
}
}
catch (Exception e)
@ -319,7 +293,6 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
public void reject(Model.SessionProposal sessionProposal, WalletConnectV2Callback callback)
{
Web3Wallet.INSTANCE.rejectSession(
new Params.SessionReject(sessionProposal.getProposerPublicKey(), context.getString(R.string.message_reject_request)),
sessionReject -> null,
@ -363,8 +336,19 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
this.actionSheetCallback = actionSheetCallback;
}
public String getRelayServer()
{
return String.format("%s/?projectId=%s", C.WALLET_CONNECT_REACT_APP_RELAY_URL, keyProvider.getWalletConnectProjectId());
}
public void init(Application application)
{
if (keyProvider.getWalletConnectProjectId().isEmpty())
{
//Early return for no wallet connect
return;
}
this.application = application;
Core.Model.AppMetaData appMetaData = getAppMetaData(application);
String relayServer = String.format("%s/?projectId=%s", C.WALLET_CONNECT_REACT_APP_RELAY_URL, keyProvider.getWalletConnectProjectId());
@ -386,6 +370,8 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
try
{
Web3Wallet.INSTANCE.setWalletDelegate(this);
//ensure notification is displayed if session is active
updateNotification(null);
}
catch (Exception e)
{
@ -394,7 +380,7 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
}
@NonNull
private Core.Model.AppMetaData getAppMetaData(Application application)
public Core.Model.AppMetaData getAppMetaData(Application application)
{
String name = application.getString(R.string.app_name);
String url = C.ALPHAWALLET_WEBSITE;
@ -466,12 +452,6 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
}
}
/*@Override
public void onAuthRequest(@NonNull Model.AuthRequest authRequest)
{
showApprovalDialog(authRequest);
}*/
private void showApprovalDialog(Model.AuthRequest authRequest)
{
String activeWallet = preferenceRepository.getCurrentWalletAddress();
@ -664,12 +644,6 @@ public class AWWalletConnectClient implements Web3Wallet.WalletDelegate
}
}
@Override
public void onSessionDelete(@NonNull Model.SessionDelete sessionDelete)
{
}
public Intent getSessionIntent(Context appContext)
{
Intent intent;

@ -265,11 +265,6 @@ public class TokenIcon extends ConstraintLayout
{
setupDefaultIcon();
if (token.tokenInfo.address.equalsIgnoreCase("0xfaafdc07907ff5120a76b34b731b278c38d6043c"))
{
System.out.println("YOLESS");
}
final RequestOptions optionalCircleCrop = squareToken || iconUrl.startsWith(ALPHAWALLET_REPO_NAME) ? new RequestOptions() : new RequestOptions().circleCrop();
currentRq = Glide.with(this)

Loading…
Cancel
Save