flutter_background_geolocation icon indicating copy to clipboard operation
flutter_background_geolocation copied to clipboard

State enabled when BackgroundGeolocation.stop() is called is not updated to false on Android

Open radivojeostojic opened this issue 3 years ago • 10 comments

I am using state.enabled to notify the user when geolocation is switched off or on: await stopTransistorsoft().then((state) => serviceActive = state.enabled);

Flag serviceActive is used to update the UI based on the geolocation tracking state. I noticed that serviceActive is true after stopTransistorsoft() is finished.

Your Environment

  • Plugin version: v4.7.0

  • Platform: Android

  • OS version: Android 12

  • Device manufacturer / model: emulator

  • Flutter info (flutter doctor): [✓] Flutter (Channel unknown, 2.10.3, on macOS 12.2.1 21D62 darwin-arm, locale en-RS) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 13.4.1) [✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome) ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable. [✓] Android Studio (version 2021.2) [✓] VS Code (version 1.68.1) [✓] Connected device (2 available) [✓] HTTP Host Availability

  • Plugin config:

await bg.BackgroundGeolocation.ready(bg.Config(
          notification: bg.Notification(
            title:'',
            // 'Location Services Active',
            text: '',
            sticky: true,
            layout: 'workday_notification_layout',
            smallIcon: 'mipmap/ic_notification',
            // <-- defaults to app icon
            largeIcon: 'mipmap/ic_notification',
          ),
          locationAuthorizationRequest: 'always',
          disableLocationAuthorizationAlert: true,
          backgroundPermissionRationale: bg.PermissionRationale(
              title: ''
              message: '',
              positiveAction: ''),
          desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
          distanceFilter: 10.0,
          stopOnTerminate: false,
          preventSuspend: true,
          heartbeatInterval: 60,
          startOnBoot: true,
          foregroundService: true,
          logLevel: bg.Config.LOG_LEVEL_ERROR,
          persistMode: bg.Config.PERSIST_MODE_NONE,
        )).then((bg.State state) {
          _initialized = true;
        });

Expected Behavior

serviceActive should be false

Actual Behavior

serviceActive is true on Android

Steps to Reproduce

  1. start and stop geolocation and check for state.enabled.

radivojeostojic avatar Jul 21 '22 13:07 radivojeostojic

The plugin has no method named stopTransistorsoft()

christocracy avatar Jul 21 '22 13:07 christocracy

The plugin has no method named stopTransistorsoft()

Sorry for the confusion. We have method stopTransistorsoft() which calls await bg.BackgroundGeolocation.stop()

radivojeostojic avatar Jul 21 '22 13:07 radivojeostojic

Now why don’t you post the source of your custom method?

christocracy avatar Jul 21 '22 13:07 christocracy

The stopTransistorsoft() method just calls stop() on geolocation without any additional work:

static Future<bg.State> stopTransistorsoft() async { return await bg.BackgroundGeolocation.stop(); }

radivojeostojic avatar Jul 21 '22 13:07 radivojeostojic

bg.State state = await bg.BackgroundGeolocation.stop();
print("************ state.enabled: ${state.enabled}");
07-21 11:47:29.629 25725 25781 I flutter : ************ state.enabled: false

christocracy avatar Jul 21 '22 15:07 christocracy

I tried also to print state.enabled value and noticed that sometimes it's false but sometimes it's true:

Code that I tested:

debugPrint('Date time: ${DateTime.now()} stopGeolocation called before with status ${serviceActive}'); await stopTransistorsoft().then((state) => serviceActive = state.enabled); debugPrint('Date time: ${DateTime.now()} stopGeolocation called after with status ${serviceActive}');

Logs:

I/flutter ( 6632): Date time: 2022-07-22 12:27:46.538818stopGeolocation called before with status true

I/flutter ( 6632): Date time: 2022-07-22 12:27:46.542683stopGeolocation called after with status true

I/flutter ( 6632): Date time: 2022-07-22 12:28:02.309110stopGeolocation called before with status true I/flutter ( 6632): Date time: 2022-07-22 12:28:02.311179stopGeolocation called after with status false

stopTransistorsoft() is:

static Future<bg.State> stopTransistorsoft() async { return await bg.BackgroundGeolocation.stop(); }

radivojeostojic avatar Jul 22 '22 10:07 radivojeostojic

I suggest you don’t test your function.

test with BackgroundGeolocation.stop()

christocracy avatar Jul 22 '22 10:07 christocracy

I received same log with this approach:

debugPrint('Date time: ${DateTime.now()} stopGeolocation called before with status ${serviceActive}'); // await stopTransistorsoft().then((state) => serviceActive = state.enabled); var state = await bg.BackgroundGeolocation.stop(); serviceActive = state.enabled; debugPrint('Date time: ${DateTime.now()} stopGeolocation called after with status ${serviceActive}');

Logs: I/flutter (10065): Date time: 2022-07-22 12:39:42.730715 stopGeolocation called before with status true I/flutter (10065): Date time: 2022-07-22 12:39:42.732919 stopGeolocation called after with status true

radivojeostojic avatar Jul 22 '22 10:07 radivojeostojic

Ok, I've reproduced this. This is merely a timing issue, where the Java implementation for .stop() executes in a background-thread but the code immediately executes the callback on the main thread.

Before

public void stop(TSCallback callback) {
        if (mStartTask != null) {
            mStartTask = null;
        }
        mIsStarted.set(false);
        getThreadPool().execute(() -> {
            TrackingService.stop(mContext);  // <-- implementation runs on a background-thread in order to not block UI
        });
        callback.onSuccess();  // <-- callback executed immediately on main-thread before background-queued .stop() executes.
    }

Fixed

public void stop(final TSCallback callback) {
        if (mStartTask != null) {
            mStartTask = null;
        }
        mIsStarted.set(false);
        getThreadPool().execute(() -> {
            TrackingService.stop(mContext);
            getUiHandler().post(callback::onSuccess);  // <-- Run callback on main-thread from within background-thread.
        });
    }

You can work-around this in the meantime by requesting .state immediately after calling .stop().

await bg.BackgroundGeolocation.stop();
bg.State state = await bg.BackgroundGeolocation.state;
print("******** State.enabled: ${state.enabled}");

Fix will arrive when 4.7.1 is released.

christocracy avatar Jul 22 '22 14:07 christocracy

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and I will leave this open.

stale[bot] avatar Sep 21 '22 05:09 stale[bot]