Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Android Camera API #3244

Closed
bleege opened this issue Dec 10, 2015 · 36 comments
Closed

Android Camera API #3244

bleege opened this issue Dec 10, 2015 · 36 comments
Assignees
Labels
Android Mapbox Maps SDK for Android

Comments

@bleege
Copy link
Contributor

bleege commented Dec 10, 2015

The next iteration of the map interaction API should be to add a Camera API. The Camera API will be modeled on the Google Maps Android API to maximize familiarity. Key classes will be:

/cc @zugaldia @incanus @twbell

@bleege bleege added the Android Mapbox Maps SDK for Android label Dec 10, 2015
@bleege bleege added this to the android-v2.4.0 milestone Dec 10, 2015
@bleege
Copy link
Contributor Author

bleege commented Dec 10, 2015

Related to #2805

@bleege
Copy link
Contributor Author

bleege commented Dec 10, 2015

Basic classes, method stubs, and a TestApp activity are built. The next step is wiring up Core GL to the method stubs and verifying via TestApp activity.

bleege added a commit that referenced this issue Dec 11, 2015
…uilding MapView's getCameraPosition() and animateCamera().
bleege added a commit that referenced this issue Dec 11, 2015
…g zoom level of CameraActivity a bit more obvious
@bleege
Copy link
Contributor Author

bleege commented Dec 11, 2015

The initial animateCamera() API is complete as of 08b5c17. The final 2 animateCamera() methods to build are related integrating Callback support and setting Animation duration. Will investigate the new flyTo() API in Core GL ( #3171 ) to see if that makes sense for these methods at this time.

bleege added a commit that referenced this issue Dec 14, 2015
…CameraActivity to support 3 use cases to align with the 3 animateCamera methods.
@bleege
Copy link
Contributor Author

bleege commented Dec 15, 2015

I refactored the CameraActivity in the TestApp to provide a visual test harness for the 3 animateCamera() methods that do the work (aka move the map) of the Camera API. The next steps will be seeing if the existing Core CL API (setCenterCoordinate(), setZoomLevel(), setTilt(new Double(), setBearing()) will be enough to implement the "move the map" part of it we'll need to wait for the flyTo methods to mature (see #3171). The original implementation done on 10-Dec-2015 in 8f6d08a did work, but since yesterday's discovery and fix of #3259 that will need to be re-verified as there's some "null island ghosting" going on when now tested.

@bleege
Copy link
Contributor Author

bleege commented Dec 15, 2015

Confirmed that the "null island ghosting" is still happening when "Animate" button is originally pressed. This appears to be an issue of setCoordinate() getting stomped on. Will review @1ec5's flyTo fixes from last night in #3301 to see if that can address it.

device-2015-12-15-100852
First Press Of Animate Button Upon CameraActivity Being Loaded

device-2015-12-15-100912
Second (and Subsequent) Presses of Animate Button In CameraActivity (Desired State)

@bleege
Copy link
Contributor Author

bleege commented Dec 15, 2015

Just did some quick testing and was able to isolate the "ghost issue" to setZoomLevel() in animateCamera().

    public final void animateCamera (CameraUpdate update) {

        // Order Matters!  Otherwise Core GL will stomp on things
        setCenterCoordinate(update.getTarget());
        setZoomLevel(update.getZoom());
        setTilt(new Double(update.getTilt()), 0L);
        setBearing(update.getBearing());
    }

@bleege
Copy link
Contributor Author

bleege commented Dec 15, 2015

I tested @1ec5's flyTo refactored code from last night this morning and think it'll be the route we should go for building out the animateCamer() methods in the Java API. @zugaldia and I discussed this and we're agreed that we'll go this route once @1ec5's PR is merged in master we will start building using it. This should happen later today. To be clear, the animateCamera() methods are the following in MapView:

public final void animateCamera (CameraUpdate update) {}
public final void animateCamera (CameraUpdate update, MapView.CancelableCallback callback) {}
public final void animateCamera (CameraUpdate update, int durationMs, MapView.CancelableCallback callback){}

@bleege
Copy link
Contributor Author

bleege commented Dec 17, 2015

Ok, thanks to @friedbunny for straightening me out it turns out that the Compass is actually working as expected. It's job in life (as it is in the iOS SDK) is to always point North no matter what the Bearing is. In this case that means the the "red arrow" part always need to be pointing North. This is not as obvious as the iOS compass has a N in it's icon which drives home the point. Needless to say, my bad on this.

Ok, so the next part on this is to clean up the debug logs, investigate how to handle the callbacks, and test out use cases where not all CameraOptions are set (ie, bearing, tilt, and zoom) behave. Once these are done this iteration of the Camera API should be complete.

bleege added a commit that referenced this issue Dec 17, 2015
@1ec5
Copy link
Contributor

1ec5 commented Dec 17, 2015

I already know that Core GL's CameraOptions.angle is in Radians. Now the trick will be to figure out it's range too.

CameraOptions.angle is in radians counter-clockwise from north. The value is wrapped to [−π rad, π rad), so you don’t have to worry about the allowable input range.

@bleege
Copy link
Contributor Author

bleege commented Dec 17, 2015

Discussed options for implementing Callbacks for animateCamera() with @zugaldia this afternoon. The best / only option available right now would be to listen for MapChange.REGION_DID_CHANGE_ANIMATED event and then fire off the Callback methods. I'll investigate using that, but if it doesn't work out we'll punt on Callbacks in the API for now.

@bleege
Copy link
Contributor Author

bleege commented Dec 17, 2015

Was able to get Callbacks working via OnMapChangedListener as previously hypothesized. Successfully tested (see screenshot below).

All that remains is to test the random / incomplete CameraOptions.

callback-test

bleege added a commit that referenced this issue Dec 17, 2015
…s. Updating TestApp's CameraActivity to test for the three different options.
@bleege
Copy link
Contributor Author

bleege commented Dec 18, 2015

Added support for optional values of bearing, tilt, and zoom in CameraOptions. Updated CameraActivity in TestApp and successfully tested.

All in all, things are looking good here. @1ec5 is working on some improvements to the flyTo() algorithm in #3296 that will improve performance (hopefully help with respect zoom issue). I'll want to look at this and the rest of the code again with some fresh eyes (including having @zugaldia give it a spin) before signing off on it and merging.

@tobrun
Copy link
Member

tobrun commented Dec 18, 2015

@bleege
Awesome progress on the feature + demonstration how to properly communicate.

Cheering from the sidelines \o/

@bleege
Copy link
Contributor Author

bleege commented Dec 18, 2015

Per chat, @zugaldia kicked the tires this morning on the branch and is happy with things. The only tweaks that we'll make are adding @UIThread annotations to the animateCamera() methods to remind everyone that these should only be used on the UI Thread as per regular Android UI conventions. As part of this we can also remove the View.post(new Runnable(){}) forced UI Thread wrapping of Callback firing command since everything will be on the UIThread.

Once these tweaks are made and tested that'll wrap up Iteration 0 on the Camera API and will then merge into master.

/cc @twbell

bleege added a commit that referenced this issue Dec 18, 2015
…() UIThread wrapping for Callback invoking. Restoring Callback Toasts in TestApp's CameraActivity.
@jfirebaugh jfirebaugh assigned jfirebaugh and unassigned bleege Dec 18, 2015
@mourner mourner assigned bleege and unassigned jfirebaugh Dec 18, 2015
@bleege
Copy link
Contributor Author

bleege commented Dec 18, 2015

Thanks to @jfirebaugh's help with git rebasing the Camera API is now merged into master for everyone to enjoy!

@mb12
Copy link

mb12 commented Dec 18, 2015

@bleege Is two finger drag gesture to tilt also available?

@bleege bleege mentioned this issue Dec 18, 2015
13 tasks
@bleege
Copy link
Contributor Author

bleege commented Dec 18, 2015

Is two finger drag gesture to tilt also available?

@mb12 Yep. That's been in there since 2.3.0.

@KidusMT
Copy link

KidusMT commented May 11, 2018

My Camera Animation is not working on API 23 and higher...but works fine on lower...Have this issue been solved? Please help!
here is my code...

// Marker
        mapboxMap.addMarker(new MarkerOptions()
                .position(new LatLng(latitude, longitude))
                .icon(icon));

        //41.900581, 12.487007 - Italy Rome
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(new LatLng(latitude, longitude)) // Sets the new camera position
                .zoom(17) // Sets the zoom
                .bearing(180) // Rotate the camera
                .tilt(30) // Set the camera tilt
                .build(); // Creates a CameraPosition from the builder

        mapboxMap.animateCamera(CameraUpdateFactory
                .newCameraPosition(cameraPosition), 7000);

here is how it's been called in the onMapReady() method

@Override
    public void onMapReady(MapboxMap mapboxMap) {
        map = mapboxMap;

        mapboxMap.setOnMarkerClickListener(this);

        //Controlling the components on the mapBox
        mapboxMap.getUiSettings().setZoomControlsEnabled(false);//hide zoom control button
        mapboxMap.getUiSettings().setCompassEnabled(false);//hide compass
        mapboxMap.getUiSettings().setZoomGesturesEnabled(true);
        mapboxMap.getUiSettings().setScrollGesturesEnabled(true);
        mapboxMap.getUiSettings().setAllGesturesEnabled(true);

        // Create an Icon object for the marker to use
        Icon icon = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.marker);

        //This is the part where we check for the whether the permissions that are needed for this
        //feature is allowed or not.
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        //Animate the camera and locate the marker
        updateMap(41.900581, 12.487007, mapboxMap, icon);
    }

@LukasPaczos
Copy link
Contributor

@KidusMT What SDK version are you using? Could you check if there are no exceptions printed in your Logcat after the map is loaded?

@KidusMT
Copy link

KidusMT commented May 12, 2018

@LukasPaczos For some reason which I am not sure why but it worked like this now

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Mapbox access token is configured here. This needs to be called either in your application

        // object or in the same activity which contains the mapview.
        Mapbox.getInstance(this, BuildConfig.MAPBOX_API_KEY);

        // This contains the MapView in XML and needs to be called after the access token is configured.
        setContentView(R.layout.activity_map);

        mapView = findViewById(R.id.mapView);

        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(mapboxMap -> {

            //Controlling the components on the mapBox
            mapboxMap.getUiSettings().setZoomControlsEnabled(false);//hide zoom control button
            mapboxMap.getUiSettings().setCompassEnabled(false);//hide compass
            mapboxMap.getUiSettings().setZoomGesturesEnabled(true);
            mapboxMap.getUiSettings().setScrollGesturesEnabled(true);
            mapboxMap.getUiSettings().setAllGesturesEnabled(true);

            mapboxMap.setOnMarkerClickListener(this);

            // Create an Icon object for the marker to use
            Icon icon = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.marker);

            updateMap(41.900581, 12.487007, mapboxMap, icon);

            //Don't forget the setCoordinate chain method is reverse while taking arguments NOTE that!

            MapboxGeocoder client = new MapboxGeocoder.Builder()
                    .setAccessToken(BuildConfig.MAPBOX_API_KEY)
                    .setCoordinates(12.487007, 41.900581)
                    .setType(GeocoderCriteria.TYPE_POI)
                    .build();

            client.enqueue(new Callback<GeocoderResponse>() {

                @Override
                public void onResponse(Response<GeocoderResponse> response, Retrofit retrofit) {
                    if (response.isSuccess()) {
                        if (response.body().getFeatures().size() > 0) {
                            placeName = response.body().getFeatures().get(0).getText();
                            String tempLocation = response.body().getFeatures().get(0).getPlaceName();
                            if (tempLocation.contains(",")) {
                                String[] places = TextUtils.split(response.body().getFeatures().get(0).getPlaceName(), ",");
                                if (places.length > 1) {
                                    address = places[1];
                                }
                            }
                        }

                    } else {
                        //TODO add something later
                    }
                }

                @Override
                public void onFailure(Throwable t) {
                }
            });


            //TODO IMPROVE THE INFO WINDOW

            mapboxMap.setInfoWindowAdapter(marker1 -> {

                View v = getLayoutInflater().inflate(R.layout.layout_callout, null);
                TextView title = v.findViewById(R.id.title);
                TextView logo = v.findViewById(R.id.logoView);
                TextView subTitle = v.findViewById(R.id.sub_title);
                if (!placeName.isEmpty()) {
                    title.setText(placeName);
                    logo.setText(placeName.substring(0, 1));
                }

                subTitle.setText(address);
                return v;

            });

            mapboxMap.setOnInfoWindowClickListener(marker -> {
                startActivity(new Intent(MapActivity.this, DetailActivity.class));
                return true;
            });

        });

     
    }

    private void updateMap(double latitude, double longitude, MapboxMap mapboxMap, Icon icon) {

        // Marker
        mapboxMap.addMarker(new MarkerOptions()
                .position(new LatLng(latitude, longitude))
                .icon(icon));


        //41.900581, 12.487007 - Italy Rome
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(new LatLng(latitude, longitude)) // Sets the new camera position
                .zoom(17) // Sets the zoom
                .bearing(180) // Rotate the camera
                .tilt(30) // Set the camera tilt
                .build(); // Creates a CameraPosition from the builder

        mapboxMap.animateCamera(CameraUpdateFactory
                .newCameraPosition(cameraPosition), 7000);

    }

this is my SDK version defined in the build config

ext.configuration = [   
        compileSdkVersion: 27,
        targetSdkVersion : 27,
        buildToolsVersion: "27.0.3"
]

now its working on all API level I am targeting to work the app for.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Android Mapbox Maps SDK for Android
Projects
None yet
Development

No branches or pull requests

9 participants