Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: KMZ support #625

Merged
merged 24 commits into from
Feb 19, 2020
Merged

feat: KMZ support #625

merged 24 commits into from
Feb 19, 2020

Conversation

jeffdgr8
Copy link
Contributor

Support opening a KMZ file through the same mechanism as opening a KML file, either from a resource ID or InputStream, in KmlLayer. Images within the KMZ archive are decoded and cached for points and ground overlays the same as downloaded images from URLs.

Fixes #619, #472

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Feb 14, 2020
This was referenced Feb 14, 2020
@arriolac arriolac self-requested a review February 18, 2020 16:42
@@ -553,7 +553,7 @@ private void putMarkerImagesCache(String url, String scale, BitmapDescriptor bit
* @param url image URL
* @param bitmap image bitmap
*/
protected void cacheBitmap(String url, Bitmap bitmap) {
public void cacheBitmap(String url, Bitmap bitmap) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert—changing the scope of cacheBitmap and checkClearBitmapCache are implementation leaks. I'll comment on KmlLayer on another suggested approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 482c748

* Use this constructor with shared object managers in order to handle multiple layers with
* their own event handlers on the map.
*
* @param map GoogleMap object
* @param stream InputStream containing KML file
* @param stream InputStream containing KML or KMZ file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be simpler if another constructor was created, with the following signature, to handle the KMZ files explicitly:

public KmlLayer(GoogleMap map, ZipInputStream stream, FragmentActivity activity, MarkerManager markerManager, PolygonManager polygonManager, PolylineManager polylineManager, GroundOverlayManager groundOverlayManager)

This way, it's left to the caller to use the correct constructor for their use-case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that. Since we can differentiate between the two types with the logic I implemented, I thought a single universal constructor was simpler for the caller to use. Also, since there are two constructors currently, the other supports opening a KML by resource ID, how could we implement opening a KMZ by resource ID? We'd have to imply the resource ID is either a KML or KMZ or we'd need the same logic to differentiate between them and call the appropriate stream constructor anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about invoking by resource ID. Let's stick to this implementation.

if (parser == null && entry.getName().toLowerCase().endsWith(".kml")) {
parser = parseKml(zip);
} else {
Bitmap bitmap = BitmapFactory.decodeStream(zip);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since other file types might also be used (e.g. .mp3), it would be good to check that an image is used and if not, log via Log.w that the file type is not supported.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this handle subdirectories?

sample.kmz
 - doc.kml
 - image.png
 - dir/image2.png
 - dir/image3.png
 - dir/dir2/image4.png
 ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, subdirectories are handled. The name includes the full file path within the zip archive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added warning log: 3d1d0e7

} else {
Bitmap bitmap = BitmapFactory.decodeStream(zip);
if (bitmap != null) {
renderer.cacheBitmap(entry.getName(), bitmap);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of caching the bitmap in KmlLayer, a helper method in KmlRenderer would be cleaner:

e.g.

KmlRenderer.storeKmzData(HashMap<String, KmlStyle> styles,
    HashMap<String, String> styleMaps,
    HashMap<KmlPlacemark, Object> features, ArrayList<KmlContainer> folders,
    HashMap<KmlGroundOverlay, GroundOverlay> groundOverlays,
    Set<String> bitmapInputStreams)

This way, all bitmap caching is done within KmlRenderer and the scoping of the functions within Renderer can be reverted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a similar method. It's not possible to pass a set of bitmap InputStreams, as each bitmap uses the same ZipInputStream as the ZipEntrys are iterated over. So I'm just passing a map of decoded bitmaps. 482c748

@arriolac arriolac self-assigned this Feb 18, 2020
Copy link
Contributor

@arriolac arriolac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing!

* Use this constructor with shared object managers in order to handle multiple layers with
* their own event handlers on the map.
*
* @param map GoogleMap object
* @param stream InputStream containing KML file
* @param stream InputStream containing KML or KMZ file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about invoking by resource ID. Let's stick to this implementation.

@arriolac arriolac merged commit 7f1dc6f into googlemaps:master Feb 19, 2020
@jeffdgr8 jeffdgr8 deleted the kmz-support branch February 20, 2020 00:39
@arriolac arriolac added this to the 1.0 milestone Feb 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

KML load images included in kmz zip file
3 participants