liodali / osm_flutter

OpenStreetMap plugin for flutter
https://pub.dev/packages/flutter_osm_plugin
MIT License
240 stars 98 forks source link

Map not showing on Android #490

Closed Alisofin closed 10 months ago

Alisofin commented 11 months ago

Hello, I upgraded from 0.42.0 version to 0.70.3. It works fine on iOS but not on Android (simulator or real device). I get the following trace: E/osm (14071): osm flutter plugin pause W/Activity(14071): Can request only one set of permissions at a time I/Geolocator(14071): The grantResults array is empty. This can happen when the user cancels the permission request E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. D/EGL_emulation(14071): app_time_stats: avg=154.35ms min=31.69ms max=438.63ms count=7 W/riends.birdyca(14071): Suspending all threads took: 8.514ms E/FrameEvents(14071): updateAcquireFence: Did not find frame. D/EGL_emulation(14071): app_time_stats: avg=89.92ms min=36.25ms max=161.53ms count=12 D/EGL_emulation(14071): app_time_stats: avg=3071.21ms min=21.83ms max=23359.46ms count=8 E/FrameEvents(14071): updateAcquireFence: Did not find frame. E/FrameEvents(14071): updateAcquireFence: Did not find frame. I/riends.birdyca(14071): Background concurrent copying GC freed 57689(4846KB) AllocSpace objects, 28(1008KB) LOS objects, 49% free, 5920KB/11MB, paused 11.068ms,11.460ms total 1.750s D/EGL_emulation(14071): app_time_stats: avg=450.66ms min=102.51ms max=677.55ms count=3 E/FrameEvents(14071): updateAcquireFence: Did not find frame. D/EGL_emulation(14071): app_time_stats: avg=559.40ms min=103.90ms max=1589.95ms count=4 D/EGL_emulation(14071): app_time_stats: avg=642.07ms min=69.89ms max=1620.92ms count=3

my code is:



class ViewCamerasMap extends StatefulWidget {
  const ViewCamerasMap({Key? key}) : super(key: key);

  @override
  _ViewCamerasMapState createState() => _ViewCamerasMapState();
}

class _ViewCamerasMapState extends State<ViewCamerasMap> with OSMMixinObserver {
  late CustomController controller;
  late GlobalKey<ScaffoldState> scaffoldKey;
  Key mapGlobalkey = UniqueKey();
  ValueNotifier<bool> zoomNotifierActivation = ValueNotifier(false);
  ValueNotifier<bool> visibilityZoomNotifierActivation = ValueNotifier(false);
  ValueNotifier<bool> advPickerNotifierActivation = ValueNotifier(false);
  ValueNotifier<bool> trackingNotifier = ValueNotifier(false);
  ValueNotifier<bool> showFab = ValueNotifier(true);
  ValueNotifier<GeoPoint?> lastGeoPoint = ValueNotifier(null);
  Timer? timer;
  int x = 0;

  late double latitude;
  late double longitude;

  bool _mapIsReady = false;
  List<Camera> _sharedCameras = [];
  List<GeoPoint> _markersList = [];
  late GeoPoint _userLocation;

  /// **********************************************************************
  /// init - Executed only 1 time before display
  /// **********************************************************************
  @override
  void initState() {
    super.initState();

    controller = CustomController(initMapWithUserPosition: true);
    controller.addObserver(this);
    controller.enableTracking();
    getUserLocation();
    scaffoldKey = GlobalKey<ScaffoldState>();
    _getSharedCamerasList();

  }

  Future getUserLocation() async {
    // Set Paris coordinates by default
    double latitude = 48.866;
    double longitude = 2.333;

    final location = Location();
    await location.getLocation()
        .then((value) {
      latitude = value.latitude;
      longitude = value.longitude;
    })
        .onError((error, stackTrace) {
      // Returns Paris coordinates by default
      print("onShelterClicked - getUserLocation - error = $error");
    });

    _userLocation = GeoPoint(latitude: latitude, longitude: longitude);
  }

  Future<void> _getSharedCamerasList() async {
    _sharedCameras = await Provider.of<PhotoService>(context, listen: false).getSharedCameras();
    print("ViewCamerasMap - _getSharedCamerasList - sharedCamerasList = ${_sharedCameras}");
  }

  /// **********************************************************************
  /// Build
  /// **********************************************************************
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      resizeToAvoidBottomInset: false,

      appBar: appBar(context),

      floatingActionButton: (_mapIsReady)
          ? gotoMyPosition(context)
          : null,

      body: Container(
        child: Stack(
          children: [
            OSMFlutter(
              controller: controller,
              osmOption: OSMOption(
                userTrackingOption: UserTrackingOption(enableTracking: false),
                showZoomController: true,
              ),

              mapIsLoading: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    CircularProgressIndicator(),
                    Text((AppLocalizations.of(context) == null)
                        ? "Map is loading..."
                        : AppLocalizations.of(context)!.viewCamerasMapIsLoading),
                  ],
                ),
              ),

              onMapIsReady: (isReady) {
                if (isReady) {
                  print("onShelterClicked - build - map is ready");
                  setState(() {
                    _mapIsReady = true;
                  });
                }
              },
              /// Handling click on marker
              onGeoPointClicked: (geoPoint) {
                onShelterClicked(geoPoint);
              },

            ),

          ],
        ),
      ),
    );
  }

  /// **********************************************************************
  /// Top application bar
  /// **********************************************************************
  AppBar appBar(BuildContext context) {
    return AppBar(
      title: Text((AppLocalizations.of(context) == null)
          ? "Shared cameras"
          : AppLocalizations.of(context)!.viewCamerasMapTitle),

    );
  }

  /// **********************************************************************
  /// Show user's position on the map
  /// **********************************************************************
  FloatingActionButton gotoMyPosition(BuildContext context) {
    return FloatingActionButton(
      onPressed: () async {
        print("onShelterClicked - gotoMyPosition - await current location");
        await controller.goToLocation(_userLocation);
        //await controller.setZoom(zoomLevel: 10);
        setState(() {
        });
      },
      child: const FaIcon(FontAwesomeIcons.locationCrosshairs),
    )
    ;
  }

  /// **********************************************************************
  /// Handle click on shelter => goto display the shelter shared images
  /// **********************************************************************
  void onShelterClicked(GeoPoint geoPoint) {

    print("ViewCamerasMap - onShelterClicked - geoPoint = $geoPoint");

    //final sharedSheltersList = Provider.of<PhotoService>(context, listen: false).sharedSheltersList;

    try {
      // Find the clicked shelter
      Camera? clickedCamera = _sharedCameras.firstWhereOrNull((camera) =>
      (double.parse(camera.latitude!) == geoPoint.latitude) &&
          (double.parse(camera.longitude!) == geoPoint.longitude));

      if (clickedCamera != null) {
        // Display the page
        print("ViewCamerasMap - onShelterClicked - Selected camera ID = ${clickedCamera.cameraID}");
        Navigator.push(context, MaterialPageRoute(
            builder: (BuildContext context) => ViewSharedPhotos(camera: clickedCamera)));

      } else {
        print("ViewCamerasMap - onShelterClicked - No camera found under the click");
      }

    } catch (e) {
      print("error $e");
    }

  }

  /// **********************************************************************
  /// Prepare the map with markers
  /// **********************************************************************
  @override
  Future<void> mapIsReady(bool isReady) async {
    if (isReady) {
      print("ViewCamerasMap - mapIsReady");
      _mapIsReady = true;
      await mapIsInitialized();
    }
  }

  Future<void> mapIsInitialized() async {
    await controller.setZoom(zoomLevel: 2.1);
    final bounds = await controller.bounds;
    print(bounds.toString());
    // Set up all shared shelters as geo point to be displayed
    await _buildCamerasGeoPoint();
    print("ViewCamerasMap - mapIsInitialized completed");

  }

  Future<void> _buildCamerasGeoPoint() async {

    // Remove all markers
    if (_markersList.isNotEmpty) {
      _markersList.forEach( (marker) async {
        await controller.removeMarker(marker);
      });
    }

    _sharedCameras.forEach((camera) async {
      print("ViewCamerasMap - _buildCamerasGeoPoint - Adding geopoint camera: ${camera.label}");
      try {
        final geoPoint = GeoPoint(
          latitude: double.parse(camera.latitude!),
          longitude: double.parse(camera.longitude!),
        );
        await controller.addMarker(
            geoPoint,
            markerIcon: MarkerIcon(assetMarker: AssetMarker(image: camera.iconPath())));
      } catch(e) {
        print("ViewCamerasMap - _buildCamerasGeoPoint - Error = $e");
      }

    });

  }

  @override
  Future<void> mapRestored() async {
    super.mapRestored();
    print("mapRestored");
    print("log map restored");
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

}

class CustomController extends MapController {
  CustomController({
    bool initMapWithUserPosition = true,
    GeoPoint? initPosition,
    BoundingBox? areaLimit = const BoundingBox.world(),
  })  : assert(
  initMapWithUserPosition || initPosition != null,
  ),
        super(
        initMapWithUserPosition: UserTrackingOption(),
        initPosition: initPosition,
        areaLimit: areaLimit,
      );

  @override
  void init() {
    super.init();
  }

}```

Many thanks for your help.
liodali commented 11 months ago

when app open do you get gps permission request ?

Alisofin commented 11 months ago

Yes. This is trace when I connect a real device: /osm (14954): osm flutter plugin pause W/Activity(14954): Can request only one set of permissions at a time I/Geolocator(14954): The grantResults array is empty. This can happen when the user cancels the permission request E/FrameEvents(14954): updateAcquireFence: Did not find frame. I/ViewRootImpl@f7e7274MainActivity: MSG_WINDOW_FOCUS_CHANGED 0 0 E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. D/TrafficStats(14954): tagSocket(122) with statsTag=0xffffffff, statsUid=-1 D/TrafficStats(14954): tagSocket(175) with statsTag=0xffffffff, statsUid=-1 E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. D/InputTransport(14954): Input channel destroyed: 'ClientS', fd=134 E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. E/FrameEvents(14954): updateAcquireFence: Did not find frame. D/CompatibilityChangeReporter(14954): Compat change id reported: 78294732; UID 10391; state: ENABLED I/ViewRootImpl@f7e7274MainActivity: stopped(false) old = false E/osm (14954): osm flutter plugin resume I/DecorView(14954): notifyKeepScreenOnChanged: keepScreenOn=false I/MSHandlerLifeCycle(14954): removeMultiSplitHandler: no exist. decor=DecorView@cb5f26b[MainActivity] I/ViewRootImpl@f7e7274MainActivity: performTraversals params={(0,0)(fillxfill) sim={adjust=resize forwardNavigation} ty=BASE_APPLICATION fmt=TRANSLUCENT wanim=0x1030001 I/ViewRootImpl@f7e7274MainActivity: fl=81810100 I/ViewRootImpl@f7e7274MainActivity: pfl=16020040 I/ViewRootImpl@f7e7274MainActivity: vsysui=510 I/ViewRootImpl@f7e7274MainActivity: apr=LIGHT_NAVIGATION_BARS I/ViewRootImpl@f7e7274MainActivity: bhv=DEFAULT I/ViewRootImpl@f7e7274MainActivity: fitSides= naviIconColor=0} I/ViewRootImpl@f7e7274MainActivity: performTraversals mFirst=false windowShouldResize=false viewVisibilityChanged=false mForceNextWindowRelayout=false params={(0,0)(fillxfill) sim={adjust=resize forwardNavigation} ty=BASE_APPLICATION fmt=TRANSLUCENT wanim=0x1030001 I/ViewRootImpl@f7e7274MainActivity: fl=81810100 I/ViewRootImpl@f7e7274MainActivity: pfl=16020040 I/ViewRootImpl@f7e7274MainActivity: vsysui=510 I/ViewRootImpl@f7e7274MainActivity: apr=LIGHT_NAVIGATION_BARS I/ViewRootImpl@f7e7274MainActivity: bhv=DEFAULT I/ViewRootImpl@f7e7274MainActivity: fitSides= naviIconColor=0} I/ViewRootImpl@f7e7274MainActivity: updateBlastSurfaceIfNeeded mBlastBufferQueue=0xb400007da0325000 isSameSurfaceControl=true I/BLASTBufferQueue(14954): update, w= 1080 h= 2408 mName = ViewRootImpl@f7e7274[MainActivity] mNativeObject= 0xb400007da0325000 sc.mNativeObject= 0xb400007d1fabdf40 format= -3 caller= android.view.ViewRootImpl.updateBlastSurfaceIfNeeded:2898 android.view.ViewRootImpl.relayoutWindow:9847 android.view.ViewRootImpl.performTraversals:3884 android.view.ViewRootImpl.doTraversal:3116 android.view.ViewRootImpl$TraversalRunnable.run:10885 android.view.Choreographer$CallbackRecord.run:1301 I/ViewRootImpl@f7e7274MainActivity: Relayout returned: old=(0,0,1080,2408) new=(0,0,1080,2408) req=(1080,2408)0 dur=14 res=0x0 s={true 0xb400007dad275000} ch=false seqId=0 I/ViewRootImpl@f7e7274MainActivity: updateBoundsLayer: t = android.view.SurfaceControl$Transaction@b87c996 sc = Surface(name=Bounds for - com.birdsandfriends.birdycam/com.birdsandfriends.birdycam.MainActivity@0)/@0x840b917 frame = 89 I/ViewRootImpl@f7e7274MainActivity: mWNT: t=0xb400007dad3dbe00 mBlastBufferQueue=0xb400007da0325000 fn= 89 caller= android.view.ViewRootImpl.prepareSurfaces:2985 android.view.ViewRootImpl.performTraversals:4233 android.view.ViewRootImpl.doTraversal:3116 E/FrameEvents(14954): updateAcquireFence: Did not find frame. I/ViewRootImpl@f7e7274MainActivity: MSG_WINDOW_FOCUS_CHANGED 1 0 I/ViewRootImpl@f7e7274MainActivity: mThreadedRenderer.initializeIfNeeded()#2 mSurface={isValid=true 0xb400007dad275000} D/InputMethodManager(14954): startInputInner - Id : 0 I/InputMethodManager(14954): startInputInner - mService.startInputOrWindowGainedFocus I/ViewRootImpl@f7e7274MainActivity: ViewPostIme pointer 0 I/ViewRootImpl@f7e7274MainActivity: ViewPostIme pointer 1 I/TRuntime.CctTransportBackend(14954): Making request to: https://firebaselogging.googleapis.com/v0cc/log/batch?format=json_proto3 D/TrafficStats(14954): tagSocket(130) with statsTag=0xffffffff, statsUid=-1 I/TRuntime.CctTransportBackend(14954): Status Code: 200

liodali commented 11 months ago

you dont need to use this onMapIsReady in OSMFlutter you already calling mapIsReady and also try to use ValueNotifier for _mapIsReady another question is loading widget dispear or continue loading ?

Alisofin commented 11 months ago

The loading widget keeps spinning.

liodali commented 11 months ago

try to remove setState from onMapIsReady

Alisofin commented 11 months ago

Done but it does not change anything. A few months ago, it was you who helped me with this code (thank you): the purpose was to show fixed geopoints with a specific icon on which you can click to reveal information. Maybe, there is another way to do it ?

Alisofin commented 11 months ago

Another idea: in the previous version I used androidHotReloadSupport: true. In the current one, I haven't seen it.

liodali commented 11 months ago

yeah we dont need it anymore the flutter team fix the issue related to the context I will check why thats happen to you and return back with solution

liodali commented 11 months ago

try latest version we fixed issue related to the user location 0.70.4

Alisofin commented 11 months ago

Unfortunately, it still doesn't work.

liodali commented 11 months ago

I found the issue, i will publish new version tomorrow i will publish hotfix or i will publish dev version because i was working on ios side so maybe its time to publish dev version to see if everything works fine sorry for being late

Alisofin commented 11 months ago

thanks, you're the best !

Alisofin commented 11 months ago

I'm trying to reference your dev version in pubscpec.yaml, this way: flutter_osm_plugin:
git: url: https://github.com/liodali/osm_flutter.git ref: 1.0.0-dev

but I got the following error message: Error on line 22, column 11: Invalid description in the "flutter_osm_plugin" pubspec on the "flutter_osm_interface" dependency: "./flutter_osm_interface" is a relative path, but this isn't a local pubspec.

liodali commented 11 months ago

I will publish dev version tomorrow you can test it sorry for being late i faced small bug in ios side thats prevent me from publish anything

liodali commented 11 months ago

check latest : 1.0.0-dev.1

Alisofin commented 11 months ago

I have troubles accessing your branch with Flutter. I can't find 1.0.0-dev.1 and when I try 1.0.0-dev (the only one visible in Github) with this in pubspec.yaml flutter_osm_plugin: git: url: https://github.com/liodali/osm_flutter.git ref: 1.0.0-dev

I got the following error in Pub Get: Error on line 22, column 11: Invalid description in the "flutter_osm_plugin" pubspec on the "flutter_osm_interface" dependency: "./flutter_osm_interface" is a relative path, but this isn't a local pubspec.

I guess the reference in pubspec.yaml is not correct.

liodali commented 11 months ago

use directly the version i published dev version for test it almost ready just miss some api like draw shape in ios

Alisofin commented 11 months ago

So, the map is displayed but there are 2 issues:

  1. the user location is not the right one.
  2. the geopoints are not displayed.

Future _buildCamerasGeoPoint() async {

// Remove all markers
if (_markersList.isNotEmpty) {
  _markersList.forEach( (marker) async {
    await controller.removeMarker(marker);
  });
}

_sharedCameras.forEach((camera) async {
  print("ViewCamerasMap - _buildCamerasGeoPoint - Adding geopoint camera: ${camera.label}");
  try {
    final geoPoint = GeoPoint(
      latitude: double.parse(camera.latitude!),
      longitude: double.parse(camera.longitude!),
    );
    await controller.addMarker(
        geoPoint,
        markerIcon: MarkerIcon(assetMarker: AssetMarker(image: camera.iconPath())));
  } catch(e) {
    print("ViewCamerasMap - _buildCamerasGeoPoint - Error = $e");
  }

});

The error is: I/flutter (23506): ViewCamerasMap - _buildCamerasGeoPoint - Error = Exception: Invalid image dimensions.

liodali commented 11 months ago

what do you mean user location is not the right one ?

liodali commented 11 months ago

if you have mutliple markers with the same icon you can use staticPosition better

Alisofin commented 11 months ago

ok, first I wish you a happy new year 224 and keep doing the good work ! I have changed my markers and it works fine on Android, but I have a new issue on iOS: when I click on a GeoPoint, it is not recognised any more

Alisofin commented 11 months ago

Besides, on iOs the loading/preparation phase of the map is very long, much longer than on Android

liodali commented 11 months ago

for iOS because initialisation happen on 2 phases maybe thats way i will try to improved and I will check the issue of geoPoint you mean you switched to staticPoints ?

Alisofin commented 11 months ago

No because my GeoPoints may not have the same icon. I have found a difference between the dev version and the latest release explaining why my GeoPoints are not identified by click . When I build the list of GeoPoints, I do this for each point: final geoPoint = GeoPoint( latitude: double.parse(camera.latitude), longitude: double.parse(camera.longitude) Latitude and longitude of the GeoPoint are stored with the same precision (limited to 2 digits) than the camera. In the release, the clicked GeoPoint given by onShelterClicked() has exactly the value than the one stored previously. In the dev version, for iOS, the clicked GeoPoint has full accuracy value (double with something like 9 or 10 digits): when I compare it, I can't find the corresponding camera.

liodali commented 11 months ago

you bring the geo marker from another place or you're using the map to store those location ? you can use precision 1/1e6 (0.000001) for comparison

liodali commented 11 months ago

I will update the == operation for GeoPoint like this

 @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is GeoPoint &&
          runtimeType == other.runtimeType &&
          longitude - other.longitude <= 1e-6 &&
          latitude - other.latitude<= 1e-6;

and i will add extension method isEqual where you can customize precision value

liodali commented 10 months ago

try our latest dev version 1.0.0-dev.3 we added isEqual and its better to store location with precision 1e-6

Alisofin commented 10 months ago

It works fine now on both iOS and Android. Many thanks