diff options
Diffstat (limited to 'android')
| -rw-r--r-- | android/app/build.gradle | 4 | ||||
| -rw-r--r-- | android/app/src/main/AndroidManifest.xml | 119 | ||||
| -rw-r--r-- | android/app/src/main/java/io/coinos/MainActivity.java | 179 |
3 files changed, 189 insertions, 113 deletions
diff --git a/android/app/build.gradle b/android/app/build.gradle index 4d3dacf9..e419e70f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "io.coinos" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 7 - versionName "1.0.7" + versionCode 8 + versionName "1.0.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 97c0e655..72d7ccc0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,60 +7,80 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - <activity - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" - android:name=".MainActivity" - android:label="@string/title_activity_main" - android:theme="@style/AppTheme.NoActionBarLaunch" - android:launchMode="singleTask" - android:exported="true"> - - <!-- Launcher intent --> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> + <activity + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" + android:name=".MainActivity" + android:label="@string/title_activity_main" + android:theme="@style/AppTheme.NoActionBarLaunch" + android:launchMode="singleTask" + android:exported="true"> + + <!-- Launcher intent --> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> - <!-- bitcoin: scheme --> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="bitcoin" /> - </intent-filter> + <!-- bitcoin: scheme --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="bitcoin" /> + </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="bitcoin" /> + </intent-filter> - <!-- lightning: scheme --> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="lightning" /> - </intent-filter> + <!-- lightning: scheme --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="lightning" /> + </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="lightning" /> + </intent-filter> - <!-- lnurl: scheme --> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="lnurl" /> - </intent-filter> + <!-- lnurl: scheme --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="lnurl" /> + </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="lnurl" /> + </intent-filter> - <!-- nostr: scheme --> - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="nostr" /> - </intent-filter> + <!-- nostr: scheme --> + <intent-filter> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="nostr" /> + </intent-filter> + <intent-filter> + <action android:name="android.nfc.action.NDEF_DISCOVERED" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="nostr" /> + </intent-filter> - <!-- Deep linking to https://coinos.io --> - <intent-filter android:autoVerify="true"> - <action android:name="android.intent.action.VIEW" /> - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - <data android:scheme="https" android:host="coinos.io" /> - </intent-filter> - </activity> + <!-- Deep linking to https://coinos.io --> + <intent-filter android:autoVerify="true"> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" android:host="coinos.io" /> + </intent-filter> + </activity> <provider android:name="androidx.core.content.FileProvider" @@ -72,7 +92,6 @@ </application> <!-- Permissions --> - <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true"/> diff --git a/android/app/src/main/java/io/coinos/MainActivity.java b/android/app/src/main/java/io/coinos/MainActivity.java index 7f710952..aaf59abe 100644 --- a/android/app/src/main/java/io/coinos/MainActivity.java +++ b/android/app/src/main/java/io/coinos/MainActivity.java @@ -2,80 +2,137 @@ package io.coinos; import com.getcapacitor.BridgeActivity; import com.getcapacitor.Bridge; -import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginHandle; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.Parcelable; import android.webkit.CookieManager; import android.webkit.WebView; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; + +import java.nio.charset.Charset; +import java.util.Arrays; + public class MainActivity extends BridgeActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = bridge.getWebView(); + CookieManager cookieManager = CookieManager.getInstance(); + cookieManager.setAcceptCookie(true); + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setDomStorageEnabled(true); + + handleIntent(getIntent()); + } + + @Override + public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + handleIntent(intent); + } + + private void handleIntent(Intent intent) { + if (intent == null) return; - WebView webView = bridge.getWebView(); - CookieManager cookieManager = CookieManager.getInstance(); - cookieManager.setAcceptCookie(true); - webView.getSettings().setJavaScriptEnabled(true); - webView.getSettings().setDomStorageEnabled(true); + String action = intent.getAction(); + Uri data = null; - Intent intent = getIntent(); - if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { - Uri data = intent.getData(); - if (data != null) { - String url = data.toString(); - Bridge bridge = getBridge(); - - if (bridge != null) { - String encodedUrl = Uri.encode(url); - String destinationUrl = "https://coinos.io/send/" + encodedUrl; + if (Intent.ACTION_VIEW.equals(action)) { + data = intent.getData(); + } else if ("android.nfc.action.NDEF_DISCOVERED".equals(action)) { + Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMsgs != null && rawMsgs.length > 0) { + NdefMessage ndefMessage = (NdefMessage) rawMsgs[0]; + for (NdefRecord record : ndefMessage.getRecords()) { + if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN && + Arrays.equals(record.getType(), NdefRecord.RTD_URI)) { - bridge.getWebView().post(() -> { - bridge.getWebView().loadUrl(destinationUrl); - }); - } - } - } - } + byte[] payload = record.getPayload(); + byte prefix = payload[0]; + String uriPrefix = resolveUriPrefix(prefix); + String uriBody = new String(Arrays.copyOfRange(payload, 1, payload.length), Charset.forName("UTF-8")); + data = Uri.parse(uriPrefix + uriBody); + break; + } + } + } + } - @Override - public void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { - Uri data = intent.getData(); - if (data != null) { - String url = data.toString(); + if (data != null) { + String url = data.toString(); + Bridge bridge = getBridge(); + if (bridge != null) { + String encodedUrl = Uri.encode(url); + String destinationUrl = "https://coinos.io/send/" + encodedUrl; - // Dispatch deep link when app is already open - Bridge bridge = getBridge(); - if (bridge != null) { - String encodedUrl = Uri.encode(url); - String destinationUrl = "https://coinos.io/send/" + encodedUrl; + bridge.getWebView().post(() -> { + bridge.getWebView().loadUrl(destinationUrl); + }); + } + } + } - bridge.getWebView().post(() -> { - bridge.getWebView().loadUrl(destinationUrl); - }); - } - } - } - } + private String resolveUriPrefix(byte prefix) { + switch (prefix) { + case 0x00: return ""; + case 0x01: return "http://www."; + case 0x02: return "https://www."; + case 0x03: return "http://"; + case 0x04: return "https://"; + case 0x05: return "tel:"; + case 0x06: return "mailto:"; + case 0x07: return "ftp://anonymous:anonymous@"; + case 0x08: return "ftp://ftp."; + case 0x09: return "ftps://"; + case 0x0A: return "sftp://"; + case 0x0B: return "smb://"; + case 0x0C: return "nfs://"; + case 0x0D: return "ftp://"; + case 0x0E: return "dav://"; + case 0x0F: return "news:"; + case 0x10: return "telnet://"; + case 0x11: return "imap:"; + case 0x12: return "rtsp://"; + case 0x13: return "urn:"; + case 0x14: return "pop:"; + case 0x15: return "sip:"; + case 0x16: return "sips:"; + case 0x17: return "tftp:"; + case 0x18: return "btspp://"; + case 0x19: return "btl2cap://"; + case 0x1A: return "btgoep://"; + case 0x1B: return "tcpobex://"; + case 0x1C: return "irdaobex://"; + case 0x1D: return "file://"; + case 0x1E: return "urn:epc:id:"; + case 0x1F: return "urn:epc:tag:"; + case 0x20: return "urn:epc:pat:"; + case 0x21: return "urn:epc:raw:"; + case 0x22: return "urn:epc:"; + case 0x23: return "urn:nfc:"; + default: return ""; + } + } - @Override - public void onPause() { - super.onPause(); - CookieManager.getInstance().flush(); - } + @Override + public void onPause() { + super.onPause(); + CookieManager.getInstance().flush(); + } - @Override - public void onBackPressed() { - WebView webView = getBridge().getWebView(); - if (webView.canGoBack()) { - webView.goBack(); - } else { - super.onBackPressed(); // Default behavior, which minimizes the app - } - } + @Override + public void onBackPressed() { + WebView webView = getBridge().getWebView(); + if (webView.canGoBack()) { + webView.goBack(); + } else { + super.onBackPressed(); + } + } } |
