diff --git a/common/build.gradle b/common/build.gradle
index b1d67f689e..b7b6cafb13 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -7,9 +7,9 @@ apply plugin: 'dagger.hilt.android.plugin'
android {
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/common/src/main/java/org/dash/wallet/common/InteractionAwareActivity.java b/common/src/main/java/org/dash/wallet/common/InteractionAwareActivity.java
index 52752b78be..2992f18cbe 100644
--- a/common/src/main/java/org/dash/wallet/common/InteractionAwareActivity.java
+++ b/common/src/main/java/org/dash/wallet/common/InteractionAwareActivity.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
@@ -33,7 +34,12 @@ public class InteractionAwareActivity extends SecureActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(FORCE_FINISH_ACTION);
- registerReceiver(forceFinishReceiver, filter);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ registerReceiver(forceFinishReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
+ } else {
+ registerReceiver(forceFinishReceiver, filter);
+ }
}
@Override
diff --git a/features/exploredash/build.gradle b/features/exploredash/build.gradle
index 200c486a66..04a47c034d 100644
--- a/features/exploredash/build.gradle
+++ b/features/exploredash/build.gradle
@@ -10,9 +10,9 @@ plugins {
android {
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
javaCompileOptions {
@@ -115,7 +115,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoVersion"
testImplementation "androidx.arch.core:core-testing:$coreTestingVersion"
- testImplementation "org.robolectric:robolectric:4.9.2"
+ testImplementation "org.robolectric:robolectric:4.13"
testImplementation "androidx.room:room-testing:$roomVersion"
androidTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoVersion"
diff --git a/integrations/coinbase/build.gradle b/integrations/coinbase/build.gradle
index 5b7f5afe21..36188c3452 100644
--- a/integrations/coinbase/build.gradle
+++ b/integrations/coinbase/build.gradle
@@ -10,9 +10,9 @@ plugins {
android {
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
diff --git a/integrations/crowdnode/build.gradle b/integrations/crowdnode/build.gradle
index f61244b6d3..14f28ad80a 100644
--- a/integrations/crowdnode/build.gradle
+++ b/integrations/crowdnode/build.gradle
@@ -10,9 +10,9 @@ plugins {
android {
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
diff --git a/integrations/uphold/build.gradle b/integrations/uphold/build.gradle
index b2cd751bf8..26be0fd8a6 100644
--- a/integrations/uphold/build.gradle
+++ b/integrations/uphold/build.gradle
@@ -9,9 +9,9 @@ plugins {
android {
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/sample-integration-android/build.gradle b/sample-integration-android/build.gradle
index 26723b640f..5aaa279088 100644
--- a/sample-integration-android/build.gradle
+++ b/sample-integration-android/build.gradle
@@ -38,9 +38,9 @@ android {
}
defaultConfig {
- compileSdk 33
+ compileSdk 34
minSdkVersion 24
- targetSdkVersion 33
+ targetSdkVersion 34
multiDexEnabled true
}
compileOptions {
diff --git a/wallet/AndroidManifest.xml b/wallet/AndroidManifest.xml
index dbadd27fe7..a51370b5e5 100644
--- a/wallet/AndroidManifest.xml
+++ b/wallet/AndroidManifest.xml
@@ -8,12 +8,14 @@
-
+
+
+
@@ -21,6 +23,7 @@
+
+ android:exported="false"
+ android:foregroundServiceType="dataSync" />
+ android:exported="false"
+ android:foregroundServiceType="connectedDevice" />
+
+
+
+
diff --git a/wallet/res/values/strings.xml b/wallet/res/values/strings.xml
index eb9c16aa2a..b3ae515ac8 100644
--- a/wallet/res/values/strings.xml
+++ b/wallet/res/values/strings.xml
@@ -331,6 +331,7 @@
You still have Dash on this device! Please be sure to write down your recovery phrase before you uninstall the Dash Wallet or you will lose your balance of %s.
Remind me later
Don\'t remind me
+ Ready to receive payments via Bluetooth
Dash balance
diff --git a/wallet/src/de/schildbach/wallet/Constants.java b/wallet/src/de/schildbach/wallet/Constants.java
index 1ca5af5c4a..34c0c07427 100644
--- a/wallet/src/de/schildbach/wallet/Constants.java
+++ b/wallet/src/de/schildbach/wallet/Constants.java
@@ -216,6 +216,7 @@ public final static class Files {
public static final int NOTIFICATION_ID_INACTIVITY = 2;
public static final int NOTIFICATION_ID_BLOCKCHAIN_SYNC = 3;
public static final int NOTIFICATION_ID_UPGRADE_WALLET = 4;
+ public static final int NOTIFICATION_ID_BLUETOOTH = 5;
public static String NOTIFICATION_CHANNEL_ID_TRANSACTIONS = "dash.notifications.transactions";
public static String NOTIFICATION_CHANNEL_ID_ONGOING = "dash.notifications.ongoing";
diff --git a/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothService.java b/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothService.java
index e5e4828f3d..9bddeaddba 100644
--- a/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothService.java
+++ b/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2015 the original author or authors.
+ * Copyright the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,47 +12,62 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*/
package de.schildbach.wallet.offline;
-import java.io.IOException;
-
-import org.bitcoinj.core.Transaction;
-import org.bitcoinj.core.VerificationException;
-import org.bitcoinj.wallet.Wallet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkNotNull;
-import dagger.hilt.android.AndroidEntryPoint;
-import de.schildbach.wallet.WalletApplication;
-import de.schildbach.wallet.service.PackageInfoProvider;
-import de.schildbach.wallet.util.CrashReporter;
-import de.schildbach.wallet.util.Toast;
-import de.schildbach.wallet_test.R;
-
-import android.app.Service;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ServiceInfo;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.text.format.DateUtils;
+import androidx.annotation.WorkerThread;
+import androidx.core.app.NotificationCompat;
+import androidx.lifecycle.LifecycleService;
+
+import org.bitcoinj.core.Transaction;
+import org.bitcoinj.core.VerificationException;
+import org.bitcoinj.wallet.Wallet;
+import org.dash.wallet.common.WalletDataProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
import javax.inject.Inject;
+import dagger.hilt.android.AndroidEntryPoint;
+import de.schildbach.wallet.Constants;
+import de.schildbach.wallet.service.PackageInfoProvider;
+import de.schildbach.wallet_test.R;
+import de.schildbach.wallet.WalletApplication;
+import de.schildbach.wallet.util.CrashReporter;
+import de.schildbach.wallet.util.Toast;
+
/**
* @author Andreas Schildbach
*/
@AndroidEntryPoint
-public final class AcceptBluetoothService extends Service {
- private WalletApplication application;
- private Wallet wallet;
+public final class AcceptBluetoothService extends LifecycleService {
+ @Inject
+ protected WalletApplication application;
+ @Inject
+ protected WalletDataProvider walletDataProvider;
+
+ @Inject
+ protected PackageInfoProvider packageInfoProvider;
private WakeLock wakeLock;
private AcceptBluetoothThread classicThread;
private AcceptBluetoothThread paymentProtocolThread;
@@ -65,16 +80,16 @@ public final class AcceptBluetoothService extends Service {
private static final Logger log = LoggerFactory.getLogger(AcceptBluetoothService.class);
- @Inject
- PackageInfoProvider packageInfoProvider;
-
@Override
public IBinder onBind(final Intent intent) {
+ super.onBind(intent);
return null;
}
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
+ super.onStartCommand(intent, flags, startId);
+
handler.removeCallbacks(timeoutRunnable);
handler.postDelayed(timeoutRunnable, TIMEOUT_MS);
@@ -87,17 +102,27 @@ public void onCreate() {
log.debug(".onCreate()");
super.onCreate();
+ final BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class);
+ final BluetoothAdapter bluetoothAdapter = checkNotNull(bluetoothManager.getAdapter());
+ final PowerManager pm = getSystemService(PowerManager.class);
- this.application = (WalletApplication) getApplication();
- this.wallet = application.getWallet();
-
- final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- getPackageName() + " bluetooth transaction submission");
+ wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
wakeLock.acquire();
+ final NotificationCompat.Builder notification = new NotificationCompat.Builder(this,
+ Constants.NOTIFICATION_CHANNEL_ID_ONGOING);
+ notification.setColor(getColor(R.color.fg_network_significant));
+ notification.setSmallIcon(R.drawable.stat_notify_bluetooth_24dp);
+ notification.setContentTitle(getString(R.string.notification_bluetooth_service_listening));
+ notification.setWhen(System.currentTimeMillis());
+ notification.setOngoing(true);
+ notification.setPriority(NotificationCompat.PRIORITY_LOW);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+ startForeground(Constants.NOTIFICATION_ID_BLUETOOTH, notification.build(),
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
+ else
+ startForeground(Constants.NOTIFICATION_ID_BLUETOOTH, notification.build());
+
registerReceiver(bluetoothStateChangeReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
try {
@@ -113,35 +138,30 @@ public boolean handleTx(final Transaction tx) {
return AcceptBluetoothService.this.handleTx(tx);
}
};
-
- classicThread.start();
- paymentProtocolThread.start();
} catch (final IOException x) {
new Toast(this).longToast(R.string.error_bluetooth, x.getMessage());
+ log.warn("problem with listening, stopping service", x);
CrashReporter.saveBackgroundTrace(x, packageInfoProvider.getPackageInfo());
+ stopSelf();
}
}
+ @WorkerThread
private boolean handleTx(final Transaction tx) {
- log.info("tx " + tx.getHashAsString() + " arrived via blueooth");
+ log.info("tx {} arrived via blueooth", tx.getTxId());
+ final Wallet wallet = walletDataProvider.getWallet();
try {
if (wallet.isTransactionRelevant(tx)) {
wallet.receivePending(tx, null);
-
- handler.post(new Runnable() {
- @Override
- public void run() {
- application.broadcastTransaction(tx);
- }
- });
+ handler.post(() -> application.broadcastTransaction(tx));
} else {
- log.info("tx " + tx.getHashAsString() + " irrelevant");
+ log.info("tx {} irrelevant", tx.getTxId());
}
return true;
} catch (final VerificationException x) {
- log.info("cannot verify tx " + tx.getHashAsString() + " received via bluetooth", x);
+ log.info("cannot verify tx " + tx.getTxId() + " received via bluetooth", x);
}
return false;
@@ -149,8 +169,10 @@ public void run() {
@Override
public void onDestroy() {
- paymentProtocolThread.stopAccepting();
- classicThread.stopAccepting();
+ if (paymentProtocolThread != null)
+ paymentProtocolThread.stopAccepting();
+ if (classicThread != null)
+ classicThread.stopAccepting();
unregisterReceiver(bluetoothStateChangeReceiver);
@@ -176,12 +198,9 @@ public void onReceive(final Context context, final Intent intent) {
}
};
- private final Runnable timeoutRunnable = new Runnable() {
- @Override
- public void run() {
- log.info("timeout expired, stopping service");
+ private final Runnable timeoutRunnable = () -> {
+ log.info("timeout expired, stopping service");
- stopSelf();
- }
+ stopSelf();
};
}
diff --git a/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothThread.java b/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothThread.java
index da7a7702f5..8d6f5be8b6 100644
--- a/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothThread.java
+++ b/wallet/src/de/schildbach/wallet/offline/AcceptBluetoothThread.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2015 the original author or authors.
+ * Copyright the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,15 +12,14 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*/
package de.schildbach.wallet.offline;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
import org.bitcoin.protocols.payments.Protos;
import org.bitcoin.protocols.payments.Protos.PaymentACK;
@@ -30,13 +29,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import de.schildbach.wallet.Constants;
import de.schildbach.wallet.util.Bluetooth;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothServerSocket;
-import android.bluetooth.BluetoothSocket;
-
/**
* @author Shahar Livne
* @author Andreas Schildbach
@@ -62,19 +62,12 @@ public void run() {
org.bitcoinj.core.Context.propagate(Constants.CONTEXT);
while (running.get()) {
- BluetoothSocket socket = null;
- DataInputStream is = null;
- DataOutputStream os = null;
-
- try {
- // start a blocking call, and return only on success or exception
- socket = listeningSocket.accept();
-
+ try ( // start a blocking call, and return only on success or exception
+ final BluetoothSocket socket = listeningSocket.accept();
+ final DataInputStream is = new DataInputStream(socket.getInputStream());
+ final DataOutputStream os = new DataOutputStream(socket.getOutputStream())) {
log.info("accepted classic bluetooth connection");
- is = new DataInputStream(socket.getInputStream());
- os = new DataOutputStream(socket.getOutputStream());
-
boolean ack = true;
final int numMessages = is.readInt();
@@ -98,30 +91,6 @@ public void run() {
os.writeBoolean(ack);
} catch (final IOException x) {
log.info("exception in bluetooth accept loop", x);
- } finally {
- if (os != null) {
- try {
- os.close();
- } catch (final IOException x) {
- // swallow
- }
- }
-
- if (is != null) {
- try {
- is.close();
- } catch (final IOException x) {
- // swallow
- }
- }
-
- if (socket != null) {
- try {
- socket.close();
- } catch (final IOException x) {
- // swallow
- }
- }
}
}
}
@@ -138,19 +107,12 @@ public void run() {
org.bitcoinj.core.Context.propagate(Constants.CONTEXT);
while (running.get()) {
- BluetoothSocket socket = null;
- DataInputStream is = null;
- DataOutputStream os = null;
-
- try {
- // start a blocking call, and return only on success or exception
- socket = listeningSocket.accept();
-
+ try ( // start a blocking call, and return only on success or exception
+ final BluetoothSocket socket = listeningSocket.accept();
+ final DataInputStream is = new DataInputStream(socket.getInputStream());
+ final DataOutputStream os = new DataOutputStream(socket.getOutputStream())) {
log.info("accepted payment protocol bluetooth connection");
- is = new DataInputStream(socket.getInputStream());
- os = new DataOutputStream(socket.getOutputStream());
-
boolean ack = true;
final Protos.Payment payment = Protos.Payment.parseDelimitedFrom(is);
@@ -171,30 +133,6 @@ public void run() {
paymentAck.writeDelimitedTo(os);
} catch (final IOException x) {
log.info("exception in bluetooth accept loop", x);
- } finally {
- if (os != null) {
- try {
- os.close();
- } catch (final IOException x) {
- // swallow
- }
- }
-
- if (is != null) {
- try {
- is.close();
- } catch (final IOException x) {
- // swallow
- }
- }
-
- if (socket != null) {
- try {
- socket.close();
- } catch (final IOException x) {
- // swallow
- }
- }
}
}
}
diff --git a/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java b/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java
index 98036b7b23..273edcf240 100644
--- a/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java
+++ b/wallet/src/de/schildbach/wallet/service/BlockchainServiceImpl.java
@@ -28,6 +28,7 @@
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.pm.ServiceInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -1074,7 +1075,11 @@ private void startForeground() {
//Shows ongoing notification promoting service to foreground service and
//preventing it from being killed in Android 26 or later
Notification notification = createNetworkSyncNotification(null);
- startForeground(Constants.NOTIFICATION_ID_BLOCKCHAIN_SYNC, notification);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+ startForeground(Constants.NOTIFICATION_ID_BLOCKCHAIN_SYNC, notification,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
+ else
+ startForeground(Constants.NOTIFICATION_ID_BLOCKCHAIN_SYNC, notification);
}
@Override
diff --git a/wallet/src/de/schildbach/wallet/ui/WalletAddressFragment.java b/wallet/src/de/schildbach/wallet/ui/WalletAddressFragment.java
index 701a547bf3..bbad2d0857 100644
--- a/wallet/src/de/schildbach/wallet/ui/WalletAddressFragment.java
+++ b/wallet/src/de/schildbach/wallet/ui/WalletAddressFragment.java
@@ -33,6 +33,7 @@
import org.dash.wallet.common.Configuration;
import de.schildbach.wallet.Constants;
import de.schildbach.wallet.WalletApplication;
+import de.schildbach.wallet.util.Nfc;
import de.schildbach.wallet.util.ThrottlingWalletChangeListener;
import de.schildbach.wallet_test.R;
@@ -61,7 +62,7 @@
/**
* @author Andreas Schildbach
*/
-public final class WalletAddressFragment extends Fragment implements NfcAdapter.CreateNdefMessageCallback {
+public final class WalletAddressFragment extends Fragment {
private Activity activity;
private WalletApplication application;
private Configuration config;
@@ -91,9 +92,6 @@ public void onAttach(final Activity activity) {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- if (nfcAdapter != null && nfcAdapter.isEnabled())
- nfcAdapter.setNdefPushMessageCallback(this, activity);
}
@Override
@@ -234,6 +232,9 @@ public void onLoadFinished(final Loader loader, final Address currentAd
currentAddressQrBitmap = Qr.INSTANCE.themeAwareDrawable(addressStr, getResources());
currentAddressUriRef.set(addressStr);
+
+ Nfc.setNdefPushMessage(nfcAdapter, createNdefMessage(addressStr), activity);
+
updateView();
}
}
@@ -243,9 +244,7 @@ public void onLoaderReset(final Loader loader) {
}
};
- @Override
- public NdefMessage createNdefMessage(final NfcEvent event) {
- final String uri = currentAddressUriRef.get();
+ private static NdefMessage createNdefMessage(final String uri) {
if (uri != null)
return new NdefMessage(new NdefRecord[] { NdefRecord.createUri(uri) });
else
diff --git a/wallet/src/de/schildbach/wallet/ui/WalletBalanceLoader.java b/wallet/src/de/schildbach/wallet/ui/WalletBalanceLoader.java
index 0ec2a3366f..16f7e6d81b 100644
--- a/wallet/src/de/schildbach/wallet/ui/WalletBalanceLoader.java
+++ b/wallet/src/de/schildbach/wallet/ui/WalletBalanceLoader.java
@@ -41,7 +41,7 @@
* @author Andreas Schildbach
*/
public final class WalletBalanceLoader extends AsyncTaskLoader {
- private LocalBroadcastManager broadcastManager;
+ private final LocalBroadcastManager broadcastManager;
private final Wallet wallet;
private static final Logger log = LoggerFactory.getLogger(WalletBalanceLoader.class);
diff --git a/wallet/src/de/schildbach/wallet/ui/payments/ReceiveFragment.kt b/wallet/src/de/schildbach/wallet/ui/payments/ReceiveFragment.kt
index 383f6c3d05..cb36dff9cd 100644
--- a/wallet/src/de/schildbach/wallet/ui/payments/ReceiveFragment.kt
+++ b/wallet/src/de/schildbach/wallet/ui/payments/ReceiveFragment.kt
@@ -37,6 +37,7 @@ import org.dash.wallet.common.ui.enter_amount.EnterAmountViewModel
import org.dash.wallet.common.ui.viewBinding
import javax.inject.Inject
+// RequestCoinsFragment in Bitcoin Wallet has the code for Bluetooth support (sharing addresses)
@AndroidEntryPoint
class ReceiveFragment : Fragment(R.layout.fragment_receive) {
private val enterAmountViewModel by activityViewModels()
diff --git a/wallet/src/de/schildbach/wallet/util/Nfc.java b/wallet/src/de/schildbach/wallet/util/Nfc.java
index 24f8ed5c6d..c3369efcbc 100644
--- a/wallet/src/de/schildbach/wallet/util/Nfc.java
+++ b/wallet/src/de/schildbach/wallet/util/Nfc.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2015 the original author or authors.
+ * Copyright the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -12,33 +12,37 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*/
package de.schildbach.wallet.util;
-import java.util.Arrays;
-
-import javax.annotation.Nullable;
-
-import com.google.common.base.Charsets;
-
+import android.app.Activity;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import androidx.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
/**
* @author Andreas Schildbach
*/
public class Nfc {
+ private static final Logger log = LoggerFactory.getLogger(Nfc.class);
+
public static NdefRecord createMime(final String mimeType, final byte[] payload) {
- final byte[] mimeBytes = mimeType.getBytes(Charsets.US_ASCII);
- final NdefRecord mimeRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
- return mimeRecord;
+ final byte[] mimeBytes = mimeType.getBytes(StandardCharsets.US_ASCII);
+ return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
}
@Nullable
public static byte[] extractMimePayload(final String mimeType, final NdefMessage message) {
- final byte[] mimeBytes = mimeType.getBytes(Charsets.US_ASCII);
+ final byte[] mimeBytes = mimeType.getBytes(StandardCharsets.US_ASCII);
for (final NdefRecord record : message.getRecords()) {
if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA && Arrays.equals(record.getType(), mimeBytes))
@@ -47,4 +51,18 @@ public static byte[] extractMimePayload(final String mimeType, final NdefMessage
return null;
}
+
+ public static void setNdefPushMessage(final NfcAdapter adapter, final NdefMessage message,
+ final Activity activity) {
+ try {
+ // reflection hack needed for Android 14 and above
+ final Method setNdefPushMessage = adapter.getClass().getMethod("setNdefPushMessage",
+ NdefMessage.class, Activity.class, Activity[].class);
+ setNdefPushMessage.invoke(adapter, message, activity, new Activity[0]);
+ } catch (final ReflectiveOperationException x) {
+ log.info("problem setting NDEF push message", x);
+ } catch (final Exception x) {
+ throw new RuntimeException(x);
+ }
+ }
}