warren-bank / Android-Mock-Location

Android app that mocks the GPS and Network location providers.
GNU General Public License v2.0
141 stars 23 forks source link

Feature - fetch GPS data from network location #23

Open tim292stro opened 2 months ago

tim292stro commented 2 months ago

I'm attempting to hook an Android OS device to a GPS 9DoF IMU that is external to the device on a wired network (USB-to-Ethernet adapter that can also charge the phone/tablet). Basically I want to feed the Android OS a mock location that is TCP pub-subbed from a network address/port. This would essentially allow a "full airplane mode" with no cellular-radio-based Assisted GPS (a battery killer) - but still providing precise location services over the hardwired data network.

I envision this mode running as a UI-less background service, with a configuration allowing an IP address and port number to be set for the GPS 9DoF IMU data, with an option to automatically use the Gateway IP from DHCP as the source, while still allowing the port to be specified. Data should ideally be a JSON format stream breaking out each data value. Since it would be providing orientation data as well 4x radio-buttons allowing the specification of "which way is up" given the current data would be needed.

The companion test bench is easy to build, a RaspberryPi Zero (Zero 2, Zero 2 W) can be put into a USB-OTG Ethernet Adapter mode, and it can run any of the services required to model data emission, or any USB-OTG ethernet adapter to a local network crossover-PC-direct can do the same.

warren-bank commented 2 months ago

thoughts:

background:

proposal:

warren-bank commented 2 months ago

note to self:

deeper dive:

warren-bank commented 2 months ago

updated proposal for diff:

import com.github.warren_bank.mock_location.service.LocationService;

// ...

    private final static String EXTRA_SILENT_UPDATE = "silent_update";

    @Override
    protected void onNewIntent(Intent intent) {
        /*
         * --------------------------------------------------
         * this section is unchanged, so I'll comment it out for clarity..
         * --------------------------------------------------

        if (intent == null) {
            handleNoData(null);
            return;
        }

        final Uri uri = intent.getData();
        if (uri == null) {
            handleNoData(null);
            return;
        }

        final String uriString = uri.toString();
        final GeoParsedPoint geoPoint = GeoPointParserUtil.parse(uriString);
        if (geoPoint == null) {
            handleNoData(getString(R.string.error_geo_intent, uriString));
            return;
        }
        if (!geoPoint.isGeoPoint()) {
            handleNoData(getString(R.string.error_geo_intent, uriString));
            return;
        }

        final LocPoint point = new LocPoint(
            geoPoint.getLatitude(),
            geoPoint.getLongitude()
        );

        * --------------------------------------------------
        */

        if (intent.getBooleanExtra(EXTRA_SILENT_UPDATE, false) && LocationService.isStarted()) {
          LocationService.doStart(GeoIntentActivity.this, true, point, null, 0);
          finish();
        }
        else {
          handleGeoData(point);
        }
    }
tim292stro commented 2 months ago

Thanks for the feedback, I'll take your point 1, and if you don't object I'll create a fork of this project and then strip it down to a background type utility.

I could see additional utility to this type of tool, just in being able to bench test any mapping app by external control - with the dev-kit remote screen capture, makes closed loop testing possible.

warren-bank commented 2 months ago

no worries.. it's GPL-2.0

Please feel free to fork and make whatever changes you like.. just be sure to share your work so others can enjoy your efforts and take it even farther.

I actually do like the idea of supporting extras in the Intent. Though I think I'll extend the Service with some public methods.. so the Activity can bind to it and call them directly. I'll probably do that this afternoon.

tim292stro commented 2 months ago

Awesome, I'll wait a bit to see what public methods you drop in before a fork (don't rush it on account of me) - and of course it would remain open/public under GPL2.0 - I believe that's clause 2(b) under that license.

warren-bank commented 2 months ago

Done. I actually opted to remove my service binder, and instead made the one class that I would want to access a static singleton. That way.. I could avoid callback hell.. and just call the methods I wanted to use synchronously. I tested it.. it works. There's some instructions in both the README and the commit message. Although.. I should mention, that the "test" described in the README using the Bookmarks app won't work right now; trying to configure the test as it is described found a tiny (but not insignificant) bug. I'm going to release a minor update of that app in a few minutes to fix the problem (with how boolean strings are parsed); currently "true" doesn't resolve to true.. because I used the wrong Java API call. woops.

update: Bookmarks is updated and now working, exactly as described.

warren-bank commented 2 months ago

fyi.. purely by happenstance.. there's another issue that was opened today and has been discussed concurrent to this one. Both are very similar, in so far as they both revolve around the idea of using the Intent to silently update the running service.

After implementing the changes mentioned in this thread, I think I might tackle something that I mentioned in the other thread. Which is to write a separate standalone app which would serve as a helper utility that:

warren-bank commented 2 months ago

I'll need to change which commit this tag is associated with.. because I've added this helper utility ("Mock Silently") to the repo in a subsequent commit, and it doesn't change either of the other pre-existing apps.. so no need for a new tag w/ rebuild.

at the moment, I haven't translated its strings yet.. but I added the APK for its english-only build to the v2.4.0 release.

I tested it out a bit.. and it works great.

update: replaced the english-only APK for one with all (51x) language translations, and updated the tag to reference the most-recent commit.

warren-bank commented 2 months ago

I did a quick search and found this..

I'm not familiar with the platform, but the overview says that it's a web app that imports/exports ".aia" files and can build APK files.

In any case, his project looks right up your alley.. might be a good starting point for reading and parsing raw GPS data from a data cable? Of course, instead of displaying the data in a UI.. you'd want to use a foreground Service that periodically starts an Intent. But that's mostly an exercise in removing unnecessary code.

warren-bank commented 2 months ago

https://github.com/freshollie/UsbGps4Droid https://github.com/freshollie/UsbGps4Droid/releases https://github.com/freshollie/UsbGps4Droid/releases/download/v2.2.1/UsbGps4Droid-v2.2.1.apk

If I'm reading this right, this app is all that you need.. it also handles the location mocking.

warren-bank commented 2 months ago

not open-source and not free, but this seems worthy of a quick mention..

warren-bank commented 2 months ago

and yet another one.. which is no-longer in the Play Store, but available on mirror sites; not open-source but seems to be free to use.. and the APK is only 51 KB.

tim292stro commented 2 months ago

So response for all 4 options you found:

First, second, and fourth ones - these are primarily for USB-to-serial GPS receivers. I need the one USB-C port for networking, so this can't work.

The third one (PilaBlu GPS Connector) is potentially a match as it specifically calls out TCPIP location data sourcing, but it's not FOSS and on reading the info and reviews it seem that most of those options aren't even available until you pay for the pro license.

I appreciate the looking and options, but I think your code is actually most suitable as a starting point - and you appear to be actively maintaining it and responding to comments so that's a bonus.

warren-bank commented 2 months ago

here is something interesting..

https://github.com/tiagoshibata/Android-GPSd-Forwarder https://f-droid.org/packages/io.github.tiagoshibata.gpsdclient/

if this is a standard data format, then this project is interesting for 2 reasons:

combine a simple data socket server.. that listens for new data.. reads byte[] and converts it back to a String.. each of which is an NMEA sentence.. then uses this parser from the earlier UsbGps4Droid project.. which does everything else: extracts location, handles location mocking and updates with each new NMEA sentence

you could either use it as-is.. or replace its internal mocking logic with some Intent logic.. to offload the mocking to this app.

to be honest.. doing it internally makes more sense. it's a special use-case.. better to use a specialized tool. mocking is actually super simple.. 99% of the work is UI.


well.. my last few comments kinda seem to have lost the plot.

for your particular use-case.. you could reuse a lot of the code in this "client" app..

that.. should do the trick

here is an explicit list of the relevant files:

tim292stro commented 2 months ago

Thanks again for this lead - and I think from your last comment you're starting to wrap your head around what I'm after.

I'm stewing on this information for a bit. It looks like there is a fairly low effort path to what I'm after. It would have been great of Google if they had just conceived of some other connection having a better location data set than the device and just putting in hooks in the OS, but at least this method gets there without needing to root a device (debug mode is "safer" as it's reversible).