LayeredLayout and Native Maps

416 views
Skip to first unread message

ballinde...@gmail.com

unread,
May 2, 2014, 11:50:49 AM5/2/14
to codenameone...@googlegroups.com
If you are experiencing an issue please mention the full platform your issue applies to:
IDE: NetBeans
Desktop OS: Windows 7
Device: Samsung Galaxy S4 (i9500) running Android 4.4.2

When using the Google Maps cn1lib on Android I've found I'm not longer able to layer buttons over the map. In the simulator with OpenStreetMap this functions as expected.

The Android build load on a Galaxy S4 hides the button.

Any ideas?

Thanks

Tim

ballinde...@gmail.com

unread,
May 2, 2014, 11:54:16 AM5/2/14
to codenameone...@googlegroups.com, ballinde...@gmail.com

package com.mycompany.myapp;


import com.codename1.googlemaps.MapContainer;
import com.codename1.io.Log;
import com.codename1.location.Location;
import com.codename1.location.LocationManager;
import com.codename1.maps.Coord;
import com.codename1.maps.MapListener;
import com.codename1.ui.Button;
import com.codename1.ui.Command;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.EncodedImage;
import com.codename1.ui.Form;
import com.codename1.ui.Label;
import com.codename1.ui.SideMenuBar;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.LayeredLayout;
import com.codename1.ui.plaf.Style;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.table.TableLayout;
import com.codename1.ui.util.Resources;
import java.io.IOException;


public class MyApplication {
   
   
private Form current;
       
   
public void init(Object context) {
       
// Pro users - uncomment this code to get crash reports sent to you automatically
       
Display.getInstance().addEdtErrorHandler(new ActionListener() {
           
public void actionPerformed(ActionEvent evt) {
                evt
.consume();
               
Log.p("Exception in AppName version " + Display.getInstance().getProperty("AppVersion", "Unknown"));
               
Log.p("OS " + Display.getInstance().getPlatformName());
               
Log.p("Error " + evt.getSource());
               
Log.p("Current Form " + Display.getInstance().getCurrent().getName());
               
Log.e((Throwable)evt.getSource());
               
Log.sendLog();
           
}
       
});
               
       
try {
           
Resources theme = Resources.openLayered("/theme");
           
UIManager.getInstance().setThemeProps(theme.getTheme(theme.getThemeResourceNames()[0]));
           
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
           
UIManager.getInstance().getLookAndFeel().setMenuBarClass(SideMenuBar.class);
       
} catch(IOException e){
            e
.printStackTrace();
       
}
     
   
}

   
public void start() {
       
if(current != null){
            current
.show();
           
return;
       
}
       
Form hi = new Form("Native Maps Test");
        hi
.setLayout(new LayeredLayout());
        hi
.setScrollable(false);
       
Container map = new Container(new BorderLayout());
       
       
final MapContainer cnt = new MapContainer();
       
final Label lbl = new Label("Location: ...");
        cnt
.addMapListener(new MapListener() {
           
public void mapPositionUpdated(Component source, int zoom, Coord center) {
               
//lbl.setText("Location: " + center.getLatitude() + ", " + center.getLongitude());
                lbl
.setText("0 lon: " + cnt.getCoordAtPosition(0, 0).getLongitude()+ " w lon " + cnt.getCoordAtPosition(Display.getInstance().getDisplayWidth(), 0).getLongitude());
           
}
       
});
        map
.addComponent(BorderLayout.SOUTH, lbl);
        map
.addComponent(BorderLayout.CENTER, cnt);
        hi
.addCommand(new Command("Move Camera") {
           
public void actionPerformed(ActionEvent ev) {
                cnt
.setCameraPosition(new Coord(-33.867, 151.206));
           
}
       
});
        hi
.addCommand(new Command("Add Marker") {
           
public void actionPerformed(ActionEvent ev) {
               
try {
                    cnt
.setCameraPosition(new Coord(41.889, -87.622));
                    cnt
.addMarker(EncodedImage.create("/maps-pin.png"), new Coord(41.889, -87.622), "Hi marker", "Optional long description", new ActionListener() {
                       
public void actionPerformed(ActionEvent evt) {
                           
Dialog.show("Marker Clicked!", "You clicked the marker", "OK", null);
                       
}
                   
});
               
} catch(IOException err) {
                   
// since the image is iin the jar this is unlikely
                    err
.printStackTrace();
               
}
           
}
       
});
        hi
.addCommand(new Command("Add Marker Here") {
           
public void actionPerformed(ActionEvent ev) {
               
try {
                    cnt
.addMarker(EncodedImage.create("/maps-pin.png"), cnt.getCameraPosition(), "Marker At", "Lat: " + cnt.getCameraPosition().getLatitude() + ", " + cnt.getCameraPosition().getLongitude(), new ActionListener() {
                       
public void actionPerformed(ActionEvent evt) {
                           
Dialog.show("Marker Clicked!", "You clicked the marker", "OK", null);
                       
}
                   
});
               
} catch(IOException err) {
                   
// since the image is iin the jar this is unlikely
                    err
.printStackTrace();
               
}
           
}
       
});
        hi
.addCommand(new Command("Add Path") {
           
public void actionPerformed(ActionEvent ev) {
                cnt
.setCameraPosition(new Coord(-18.142, 178.431));
                cnt
.addPath(new Coord(-33.866, 151.195), // Sydney
                   
new Coord(-18.142, 178.431),  // Fiji
                   
new Coord(21.291, -157.821),  // Hawaii
                   
new Coord(37.423, -122.091)  // Mountain View
               
);
           
}
       
});
        hi
.addCommand(new Command("Clear All") {
           
public void actionPerformed(ActionEvent ev) {
                cnt
.clearMapLayers();
           
}
       
});
       
        hi
.show();      
        hi
.addComponent(map);
       
       
TableLayout layout = new TableLayout(3, 3);
       
Container c = new Container();
        c
.setLayout(layout);

       
Button fetchme = new Button("Fetch me now!");
        fetchme
.setPreferredW(200);
       
Style s = new Style();
        s
.setAlignment(Label.CENTER);
        fetchme
.setUnselectedStyle(s);
       
TableLayout.Constraint constraint = layout.createConstraint(2, 2);
        constraint
.setWidthPercentage(100);
        constraint
.setHeightPercentage(90);
        constraint
.setHorizontalAlign(Component.CENTER);
        constraint
.setVerticalAlign(Component.BOTTOM);
       
        c
.addComponent(constraint, fetchme);
        hi
.addComponent(c);
       
       
LocationManager lm = LocationManager.getLocationManager();        
       
        fetchme
.setEnabled(false);
       
       
try {                    
           
Location location = lm.getCurrentLocationSync(30000);
            fetchme
.setEnabled(true);
           
            cnt
.setCameraPosition(new Coord(location.getLatitude(), location.getLongitude()));
            cnt
.zoom(new Coord(location.getLatitude(), location.getLongitude()), 16);
            cnt
.addMarker(EncodedImage.create("/maps-pin.png"), new Coord(location.getLatitude(), location.getLongitude()), "Hi marker", "Optional long description", new ActionListener() {
               
public void actionPerformed(ActionEvent evt) {
                   
// nothing
               
}
           
});                        
           
       
} catch (Exception ex) {
           
if(Display.isInitialized()) {
                   
Dialog.show(null, "Can't get location - is your GPS on?", Dialog.TYPE_ERROR, null, null, null, 2000);
           
}            
       
}
       
   
}

   
public void stop() {
        current
= Display.getInstance().getCurrent();
   
}
   
   
public void destroy() {
   
}
}
Enter code here...


Shai Almog

unread,
May 2, 2014, 1:17:17 PM5/2/14
to codenameone...@googlegroups.com, ballinde...@gmail.com
The native map is native hence its heavyweight and on top of Codename One buttons. You can't place Codename One components on top of it.

francis....@cysca.ca

unread,
May 2, 2014, 1:42:50 PM5/2/14
to codenameone...@googlegroups.com, ballinde...@gmail.com
HI Shai,

Can we presume that it's the same thing with a (heavyweight) video player?

francis....@cysca.ca

unread,
May 2, 2014, 1:44:52 PM5/2/14
to codenameone...@googlegroups.com, ballinde...@gmail.com, francis....@cysca.ca
...or how about a WebBrowser component?

Thanks!

Francis

Shai Almog

unread,
May 3, 2014, 3:44:30 AM5/3/14
to codenameone...@googlegroups.com, ballinde...@gmail.com, francis....@cysca.ca
Yes, all peer components are rendered on the native thread which runs after the EDT completed drawing. So we can't draw on top of them in the current Codename One implementation.
This architecture allows us to be extremely portable but there is a price when interacting with native widgets.

A workaround is to show a dialog on top of the widget, since a dialog is literally a separate form it can appear on top of the widget. It works by taking a screenshot of the widget and showing that in its background. It can't be used for your particular use case though.

For your use case you will need to use menu buttons or a toolbar outside of the map.

exafr...@gmail.com

unread,
Jul 2, 2014, 10:45:46 AM7/2/14
to codenameone...@googlegroups.com, francis....@cysca.ca
Would it be possible to render native buttons on top of the map, if so I will give it a bash?

Shai Almog

unread,
Jul 3, 2014, 12:05:47 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
It should be possible but you would need to do this as part of the map component itself and change the native sources of the library. That's part of why we made this as a cn1lib and didn't integrate it into the core project.

exafr...@gmail.com

unread,
Jul 3, 2014, 2:27:40 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
Thanks Shai!

It's mostly a case that my clients may ask me to do it "because other apps are able to do so".

Tim Gaul

unread,
Jul 3, 2014, 6:44:18 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
I've unfortunately stumbled across an issue that requires me to have a static image in the middle of the map at all times, a bit like a crosshair. This image must remain in the same position if I zoom in, or reposition the map. Using the MapListener this is only updated once the mouse/touch screen is released. 

Shai Almog

unread,
Jul 3, 2014, 10:45:19 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
That's an overlay or layer in map terminology. We don't have that builtin but it should be pretty trivial to add if you look at the sources.
Message has been deleted

Tim Gaul

unread,
Jul 3, 2014, 11:34:18 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
Hi Shai

Thanks, you've pointed me in the right direction. Something like this is what I'm looking for:

public class CrosshairOverlay extends Overlay {
   
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
       
Projection projection = mapView.getProjection();
       
Point center = projection.toPixels(mapView.getMapCenter(), null);

       
// Customize appearance, should be a fields.
       
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p
.setColor(0xFF000000);
        p
.setStyle(Style.STROKE);
        p
.setStrokeWidth(2.0f);
       
int innerRadius = 10;
       
int outerRadius = 20;

        canvas
.drawCircle(center.x, center.y, innerRadius, p);
        canvas
.drawCircle(center.x, center.y, outerRadius, p);
       
return true;
   
}
}

How would I go about implementing this on my native map?

Thanks!

Tim Gaul

unread,
Jul 3, 2014, 11:59:16 AM7/3/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
Thanks Shai. Taking a look, is it possible to do this without altering the cn1lib code for the native maps?


On Thursday, July 3, 2014 4:45:19 PM UTC+2, Shai Almog wrote:

Shai Almog

unread,
Jul 4, 2014, 1:23:42 AM7/4/14
to codenameone...@googlegroups.com, francis....@cysca.ca, exafr...@gmail.com
You would need to write native code, you could potentially do this via native interfaces but I think by far the simplest way would be to alter the code.

Tim Gaul

unread,
Jul 4, 2014, 2:50:17 AM7/4/14
to codenameone...@googlegroups.com, exafr...@gmail.com
Thanks Shai. I tend to agree.

It's just going to make it more difficult to integrate any changes you guys make on your side :)

Shai Almog

unread,
Jul 4, 2014, 12:22:06 PM7/4/14
to codenameone...@googlegroups.com, exafr...@gmail.com
If you create something generic you can just contribute it back.
Reply all
Reply to author
Forward
0 new messages