sandialabs / InterSpec

spectral radiation analysis software
https://sandialabs.github.io/InterSpec
GNU Lesser General Public License v2.1
126 stars 21 forks source link

enable android interspec app to receive data shared directly from radiacode app #34

Closed ckuethe closed 1 month ago

ckuethe commented 1 month ago

making a new issue so as not to clutter up #32...

The short version: maybe interspec needs to handle a SEND too, not just a VIEW. Perhaps application/xml and text/xml should both be accepted MIME types too.

I found an app on F-Droid called "intent intercept" which seems to be a general receiver/inspector for any share intent (IPC message). here's what a share from radiacode looks like:

intent:#Intent;action=android.intent.action.SEND;type=text/xml;launchFlags=0x1b080000;S.android.intent.extra.SUBJECT=RadiaCode%3A%20Spectrum;end 
------------ 
ACTION: android.intent.action.SEND 
MIME: text/xml 
URI: intent:#Intent;action=android.intent.action.SEND;type=text/xml;launchFlags=0x1b080000;S.android.intent.extra.SUBJECT=RadiaCode%3A%20Spectrum;end 
FLAGS: 
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 
FLAG_RECEIVER_FOREGROUND 
FLAG_ACTIVITY_FORWARD_RESULT 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 
EXTRAS: 
1 Class: java.lang.String 
Key: android.intent.extra.SUBJECT 
Value: RadiaCode: Spectrum 
2 Class: android.net.Uri$HierarchicalUri 
Key: android.intent.extra.STREAM 
Value: content://com.almacode.radiacode.provider/cache/Share/thq2.xml 

------------ 
MATCHING ACTIVITIES: 
Drive (com.google.android.apps.docs - com.google.android.apps.docs.common.shareitem.UploadMenuActivity) 
Bluetooth (com.google.android.bluetooth - com.android.bluetooth.opp.BluetoothOppLauncherActivity) 
Gmail (com.google.android.gm - com.google.android.gm.ComposeActivityGmailExternal) 
Quick Share (com.google.android.gms - com.google.android.gms.nearby.sharing.send.SendActivity) 
Kindle (com.amazon.kindle - com.amazon.kindle.s2k.SendToKindleActivity) 
Discord (com.discord - com.discord.share.ShareActivity) 
Nextcloud (com.nextcloud.client - com.owncloud.android.ui.activity.ReceiveExternalFilesActivity) 
eReader Prestigio (com.prestigio.ereader - com.prestigio.android.ereader.shelf.MainShelfActivity) 
Comment (com.todoist - com.todoist.activity.AddAsNoteActivity) 
GPX Viewer (com.vecturagames.android.app.gpxviewer - com.vecturagames.android.app.gpxviewer.activity.MainActivity) 
Bitwarden (com.x8bit.bitwarden - com.x8bit.bitwarden.MainActivity) 
Conversations (eu.siacs.conversations - eu.siacs.conversations.ui.ShareWithActivity) 
Element (im.vector.app - im.vector.app.features.share.IncomingShareActivity) 
Home Assistant (io.homeassistant.companion.android - io.homeassistant.companion.android.share.ShareActivity) 
Keybase (io.keybase.ossifrage - io.keybase.ossifrage.MainActivity) 
Add card (it.niedermann.nextcloud.deck - it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity) 
Add to card (it.niedermann.nextcloud.deck - it.niedermann.nextcloud.deck.ui.sharetarget.ShareTargetActivity) 
Squawker (org.ca.squawker - org.ca.squawker.MainActivity) 
Open Sudoku (org.moire.opensudoku - org.moire.opensudoku.gui.PuzzleImportActivity) 
Signal (org.thoughtcrime.securesms - org.thoughtcrime.securesms.sharing.v2.ShareActivity) 
VLC (org.videolan.vlc - org.videolan.vlc.StartActivity) 
Switch to work profile (android - com.android.internal.app.ForwardIntentToManagedProfile) 

And here's what it looks like when nextcloud shares that same file:

intent:#Intent;action=android.intent.action.SEND;type=application/xml;launchFlags=0x1b080000;end 
------------ 
ACTION: android.intent.action.SEND 
MIME: application/xml 
URI: intent:#Intent;action=android.intent.action.SEND;type=application/xml;launchFlags=0x1b080000;end 
FLAGS: 
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 
FLAG_RECEIVER_FOREGROUND 
FLAG_ACTIVITY_FORWARD_RESULT 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 
EXTRAS: 
1 Class: android.net.Uri$HierarchicalUri 
Key: android.intent.extra.STREAM 
Value: content://org.nextcloud.files/external_files/emulated/0/Android/media/com.nextcloud.client/nextcloud/ckuethe%40nextcloud.mainframe.cx/RadiaCode/thq2.xml 
Value (decoded): content://org.nextcloud.files/external_files/emulated/0/Android/media/com.nextcloud.client/nextcloud/ckuethe@nextcloud.mainframe.cx/RadiaCode/thq2.xml 

------------ 
MATCHING ACTIVITIES: 
Drive (com.google.android.apps.docs - com.google.android.apps.docs.common.shareitem.UploadMenuActivity) 
Gmail (com.google.android.gm - com.google.android.gm.ComposeActivityGmailExternal) 
Quick Share (com.google.android.gms - com.google.android.gms.nearby.sharing.send.SendActivity) 
Slack (com.Slack - slack.features.home.HomeActivity) 
Kindle (com.amazon.kindle - com.amazon.kindle.s2k.SendToKindleActivity) 
Discord (com.discord - com.discord.share.ShareActivity) 
Nextcloud (com.nextcloud.client - com.owncloud.android.ui.activity.ReceiveExternalFilesActivity) 
1Password (com.onepassword.android - com.onepassword.android.app.StartActivity) 
eReader Prestigio (com.prestigio.ereader - com.prestigio.android.ereader.shelf.MainShelfActivity) 
Comment (com.todoist - com.todoist.activity.AddAsNoteActivity) 
Task (com.todoist - com.todoist.activity.AddFileAsItemProxyActivity) 
GPX Viewer (com.vecturagames.android.app.gpxviewer - com.vecturagames.android.app.gpxviewer.activity.MainActivity) 
Bitwarden (com.x8bit.bitwarden - com.x8bit.bitwarden.MainActivity) 
Conversations (eu.siacs.conversations - eu.siacs.conversations.ui.ShareWithActivity) 
Element (im.vector.app - im.vector.app.features.share.IncomingShareActivity) 
Keybase (io.keybase.ossifrage - io.keybase.ossifrage.MainActivity) 
Add to card (it.niedermann.nextcloud.deck - it.niedermann.nextcloud.deck.ui.sharetarget.ShareTargetActivity) 
Open Sudoku (org.moire.opensudoku - org.moire.opensudoku.gui.PuzzleImportActivity) 
Create new task (org.tasks - com.todoroo.astrid.activity.ShareLinkActivity) 
Signal (org.thoughtcrime.securesms - org.thoughtcrime.securesms.sharing.v2.ShareActivity) 
VLC (org.videolan.vlc - org.videolan.vlc.StartActivity) 
Switch to work profile (android - com.android.internal.app.ForwardIntentToManagedProfile) 

Interspec is still not listed as a target for sharing, but by this time the spectrum has been synced to my phone and I can use "open with app..." which looks like this.

intent://org.nextcloud.files/external_files/emulated/0/Android/media/com.nextcloud.client/nextcloud/ckuethe%40nextcloud.mainframe.cx/RadiaCode/thq2.xml#Intent;scheme=content;type=text/xml;launchFlags=0x13400000;end 
------------ 
ACTION: android.intent.action.VIEW 
DATA: content://org.nextcloud.files/external_files/emulated/0/Android/media/com.nextcloud.client/nextcloud/ckuethe%40nextcloud.mainframe.cx/RadiaCode/thq2.xml 
MIME: text/xml 
URI: intent://org.nextcloud.files/external_files/emulated/0/Android/media/com.nextcloud.client/nextcloud/ckuethe%40nextcloud.mainframe.cx/RadiaCode/thq2.xml#Intent;scheme=content;type=text/xml;launchFlags=0x13400000;end 
FLAGS: 
FLAG_RECEIVER_FOREGROUND 
FLAG_ACTIVITY_FORWARD_RESULT 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 
FLAG_ACTIVITY_BROUGHT_TO_FRONT 

------------ 
MATCHING ACTIVITIES: 
Tracklia (app.tracklia - com.edsa.haiker.view.MapFiguresImportActivity) 
RadiaCode (com.almacode.radiacode - com.almacode.radiacode.ImportActivity) 
Flipper (com.flipperdevices.app - com.flipperdevices.singleactivity.impl.SingleActivity) 
eReader Prestigio (com.prestigio.ereader - com.prestigio.android.ereader.shelf.MainShelfActivity) 
GPX Viewer (com.vecturagames.android.app.gpxviewer - com.vecturagames.android.app.gpxviewer.activity.MainActivity) 
AovoPro (com.zydtech.aovopro - com.zydtech.aovopro.MainActivity) 
InterSpec (gov.sandia.interspec - gov.sandia.InterSpec.InterSpec) 

And that does show interspec as an eligible app. Here's the same "open with", but from Google drive.

intent://com.google.android.apps.docs.storage.legacy/enc%3Dencoded%3DuX-YB5DT8VyNEdnfThUSyqVY4TGFAMkIkGquTcGDiZ5ilUDA1hxATpFm#Intent;scheme=content;type=text/xml;launchFlags=0x3000000;end 
------------ 
ACTION: android.intent.action.VIEW 
DATA: content://com.google.android.apps.docs.storage.legacy/enc%3Dencoded%3DuX-YB5DT8VyNEdnfThUSyqVY4TGFAMkIkGquTcGDiZ5ilUDA1hxATpFm 
MIME: text/xml 
URI: intent://com.google.android.apps.docs.storage.legacy/enc%3Dencoded%3DuX-YB5DT8VyNEdnfThUSyqVY4TGFAMkIkGquTcGDiZ5ilUDA1hxATpFm#Intent;scheme=content;type=text/xml;launchFlags=0x3000000;end 
FLAGS: 
FLAG_ACTIVITY_FORWARD_RESULT 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 

------------ 
MATCHING ACTIVITIES: 
Tracklia (app.tracklia - com.edsa.haiker.view.MapFiguresImportActivity) 
Flipper (com.flipperdevices.app - com.flipperdevices.singleactivity.impl.SingleActivity) 
eReader Prestigio (com.prestigio.ereader - com.prestigio.android.ereader.shelf.MainShelfActivity) 
GPX Viewer (com.vecturagames.android.app.gpxviewer - com.vecturagames.android.app.gpxviewer.activity.MainActivity) 
AovoPro (com.zydtech.aovopro - com.zydtech.aovopro.MainActivity) 
InterSpec (gov.sandia.interspec - gov.sandia.InterSpec.InterSpec) 

And when I try to "send a copy" from Google drive, this intent is emitted, and interspec is not an available option.

intent:#Intent;action=android.intent.action.SEND;type=text/xml;launchFlags=0x1b080000;end 
------------ 
ACTION: android.intent.action.SEND 
MIME: text/xml 
URI: intent:#Intent;action=android.intent.action.SEND;type=text/xml;launchFlags=0x1b080000;end 
FLAGS: 
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 
FLAG_RECEIVER_FOREGROUND 
FLAG_ACTIVITY_FORWARD_RESULT 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 
EXTRAS: 
1 Class: android.net.Uri$HierarchicalUri 
Key: android.intent.extra.STREAM 
Value: content://com.google.android.apps.docs.storage.legacy/enc%3Dencoded%3DuX-YB5DT8VyNEdnfThUSyqVY4TGFAMkIkGquTcGDiZ5ilUDA1hxATpFm 
Value (decoded): content://com.google.android.apps.docs.storage.legacy/enc=encoded=uX-YB5DT8VyNEdnfThUSyqVY4TGFAMkIkGquTcGDiZ5ilUDA1hxATpFm 

------------ 
MATCHING ACTIVITIES: 
Drive (com.google.android.apps.docs - com.google.android.apps.docs.common.shareitem.UploadMenuActivity) 
Bluetooth (com.google.android.bluetooth - com.android.bluetooth.opp.BluetoothOppLauncherActivity) 
Gmail (com.google.android.gm - com.google.android.gm.ComposeActivityGmailExternal) 
Quick Share (com.google.android.gms - com.google.android.gms.nearby.sharing.send.SendActivity) 
Kindle (com.amazon.kindle - com.amazon.kindle.s2k.SendToKindleActivity) 
Discord (com.discord - com.discord.share.ShareActivity) 
Nextcloud (com.nextcloud.client - com.owncloud.android.ui.activity.ReceiveExternalFilesActivity) 
eReader Prestigio (com.prestigio.ereader - com.prestigio.android.ereader.shelf.MainShelfActivity) 
Comment (com.todoist - com.todoist.activity.AddAsNoteActivity) 
GPX Viewer (com.vecturagames.android.app.gpxviewer - com.vecturagames.android.app.gpxviewer.activity.MainActivity) 
Bitwarden (com.x8bit.bitwarden - com.x8bit.bitwarden.MainActivity) 
Conversations (eu.siacs.conversations - eu.siacs.conversations.ui.ShareWithActivity) 
Element (im.vector.app - im.vector.app.features.share.IncomingShareActivity) 
Home Assistant (io.homeassistant.companion.android - io.homeassistant.companion.android.share.ShareActivity) 
Keybase (io.keybase.ossifrage - io.keybase.ossifrage.MainActivity) 
Add card (it.niedermann.nextcloud.deck - it.niedermann.nextcloud.deck.ui.preparecreate.PrepareCreateActivity) 
Add to card (it.niedermann.nextcloud.deck - it.niedermann.nextcloud.deck.ui.sharetarget.ShareTargetActivity) 
Squawker (org.ca.squawker - org.ca.squawker.MainActivity) 
Open Sudoku (org.moire.opensudoku - org.moire.opensudoku.gui.PuzzleImportActivity) 
Signal (org.thoughtcrime.securesms - org.thoughtcrime.securesms.sharing.v2.ShareActivity) 
VLC (org.videolan.vlc - org.videolan.vlc.StartActivity) 
Switch to work profile (android - com.android.internal.app.ForwardIntentToManagedProfile) 

I'll look at the android code tomorrow and see if I can get a better sense of what is actually going on. Nothing helps you learn like a real project or an actual problem to solve, right?

ckuethe commented 1 month ago

Share2Storage is able to receive the share from radiacode; here is its manifest... not very selective.

https://github.com/MateusRodCosta/Share2Storage/blob/13401de762dbd994aed79c39649f91eea9948781/app/src/main/AndroidManifest.xml

wcjohns commented 1 month ago

Thanks Chris!

This looks easy-enough to do.
Those dumps of the intents are really helpful - I hadn't known what was involved in the requests.

The android documentation has sample code for receiving as well.

I'll try to give look at this sometime in the next ~week, as well as looking at the issue of the soft-keyboard potentially blocking inputs, and if both things can be resolved, release a new version for Android.

wcjohns commented 1 month ago

Does it make sense for InterSpec to also be not very selective, and basically accept any file?

For Radiacode, XML looks sufficient, and we can also put in N42, SPC, TXT, PCF, etc., but it seems sometimes people use non-standard, or missing, file extensions, and may want to open files from other apps.

Or is it rude to put InterSpec on the list when you share any file?

ckuethe commented 1 month ago

I don't think it would be rude to allow InterSpec to offer to handle arbitrary content. No worse than:

If I share a spectrum to GPX Viewer, it just gives me a polite message that "This isn't a gpx, kml, kmz, or loc file." And as you say, people could be sharing content from any other app with any name, extension, or MIME type - and SpecUtils knows how to identify a file by content, not just by name.

Screenshot_20240926-094451

wcjohns commented 1 month ago

I think accepting files directly from the Radiacode app should now be working, as of 040e7d2a7a110f209add5213270f5f77d006f42b.

I posted a build of the Android app at https://github.com/sandialabs/InterSpec/releases/tag/v1.0.13_rc1_android, but please note that if you are not using a floating keyboard (i.e., showing the keyboard changes the view size), the keyboard may cover up the input field, or maybe other layout issues - sorry, I haven't found a resolution to this yet... But if you are wiling to side-load the app and give it a try, I would appreciate.

Thanks @PlasmaHH and @ckuethe for pointing out the issue, and pointing to the solution!
It was pretty straight forward and easy to implement.

ckuethe commented 1 month ago

confirmed working with radiacode app 1.61.03, on Android 14.

share xml, select interspec app, and there it is. doesn't get much easier than that.

Thanks for the quick resolution @wcjohns

wcjohns commented 1 month ago

The keyboard issue on Android has been worked out, and an updated APK is available at https://github.com/sandialabs/InterSpec/releases/tag/v1.0.13_rc2

ckuethe commented 1 month ago

Loads file correctly from radiacode app, keyboard, view scroll, and input fields all behave reasonably. Show tool tabs works.

Screenshot_20241002-174311 Screenshot_20241002-174809

wcjohns commented 1 month ago

Thanks for checking this Chris!

ckuethe commented 1 month ago

Also works on my cheap android 11 tablet, using nextcloud as the data source. Both download+open_with, and "share/send" send data to the android app, which loads the files correctly. Keyboard and screen behave reasonably.