1
0
forked from GRIN/grim

Goblin Build 116

Floonet scoped Nym exit on the money-path relay (dial a relay operator's
co-located exit over a MixnetStream, TLS end to end, no public DNS; anchor +
fallback, never pin-only), NIP-44 v3 gift wraps (G4), mix-DNS, localization,
GUI polish. Verified end to end: two wallets complete a real gift-wrapped Grin
payment over relay.goblin.st, finalized + posted on mainnet.
This commit is contained in:
2ro
2026-07-02 04:23:06 -04:00
parent 5deffbda4c
commit 2d2bf326b3
57 changed files with 5741 additions and 950 deletions
@@ -23,6 +23,10 @@ public class BackgroundService extends Service {
private boolean mStopped = false;
private static final int NOTIFICATION_ID = 1;
// One-shot "payment received" notification, separate from the persistent
// sync notification above.
private static final int PAYMENT_NOTIFICATION_ID = 2;
private static final String PAYMENT_CHANNEL_ID = "PaymentReceived";
private NotificationCompat.Builder mNotificationBuilder;
private String mNotificationContentText = "";
@@ -189,6 +193,40 @@ public class BackgroundService extends Service {
notificationManager.cancel(NOTIFICATION_ID);
}
// Show a one-shot "payment received" notification (id=2), separate from
// the persistent sync notification (id=1). Called from native code via
// MainActivity when a payment slatepack is received over nostr, possibly
// while the app is backgrounded. Localization of the fixed strings is a
// follow-up (text is composed here at Java side).
public static void notifyPaymentReceived(Context context, String name, String amount) {
NotificationManager manager = context.getSystemService(NotificationManager.class);
if (manager == null) {
return;
}
// High-importance channel so the notification pops with sound + vibration.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
PAYMENT_CHANNEL_ID, "Payments", NotificationManager.IMPORTANCE_HIGH
);
manager.createNotificationChannel(channel);
}
Intent i = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, i, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, PAYMENT_CHANNEL_ID)
.setContentTitle("Payment received")
.setContentText(name + " paid " + amount + "")
.setSmallIcon(R.drawable.ic_stat_name)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setContentIntent(pendingIntent);
try {
manager.notify(PAYMENT_NOTIFICATION_ID, builder.build());
} catch (SecurityException e) {
// POST_NOTIFICATIONS not granted: skip the notification, never the payment.
}
}
// Start the service.
public static void start(Context c) {
if (!isServiceRunning(c)) {
@@ -421,6 +421,12 @@ public class MainActivity extends GameActivity {
// Notify native code to stop activity (e.g. node) if app was terminated from recent apps.
public native void onTermination();
// Called from native code to show a "payment received" notification
// (BackgroundService id=2) when a payment arrives over nostr.
public void notifyPaymentReceived(String name, String amount) {
BackgroundService.notifyPaymentReceived(this, name, amount);
}
// Called from native code to set text into clipboard.
public void copyText(String data) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
@@ -619,7 +625,12 @@ public class MainActivity extends GameActivity {
// Called from native code to pick the file.
public void pickFile() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/*");
// Permissive type: custom extensions like .backup have no registered
// MIME type, so any narrower filter greys them out in the picker and
// locks users out of restoring their identity. Content is validated
// on the native side after selection.
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
mFilePickResult.launch(Intent.createChooser(intent, "Pick file"));
} catch (android.content.ActivityNotFoundException ex) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB