15
15
*/
16
16
package com .google .maps .android .data .kml ;
17
17
18
+ import android .graphics .Bitmap ;
19
+ import android .graphics .BitmapFactory ;
20
+ import android .util .Log ;
21
+
18
22
import androidx .fragment .app .FragmentActivity ;
19
23
20
24
import com .google .android .gms .maps .GoogleMap ;
28
32
import org .xmlpull .v1 .XmlPullParserException ;
29
33
import org .xmlpull .v1 .XmlPullParserFactory ;
30
34
35
+ import java .io .BufferedInputStream ;
31
36
import java .io .IOException ;
32
37
import java .io .InputStream ;
38
+ import java .util .HashMap ;
39
+ import java .util .zip .ZipEntry ;
40
+ import java .util .zip .ZipInputStream ;
33
41
34
42
/**
35
43
* Document class allows for users to input their KML data and output it onto the map
@@ -39,8 +47,10 @@ public class KmlLayer extends Layer {
39
47
/**
40
48
* Creates a new KmlLayer object - addLayerToMap() must be called to trigger rendering onto a map.
41
49
*
50
+ * Constructor may be called on a background thread, as I/O and parsing may be long-running.
51
+ *
42
52
* @param map GoogleMap object
43
- * @param resourceId Raw resource KML file
53
+ * @param resourceId Raw resource KML or KMZ file
44
54
* @param activity Activity object
45
55
* @throws XmlPullParserException if file cannot be parsed
46
56
* @throws IOException if I/O error
@@ -53,8 +63,10 @@ public KmlLayer(GoogleMap map, int resourceId, FragmentActivity activity)
53
63
/**
54
64
* Creates a new KmlLayer object - addLayerToMap() must be called to trigger rendering onto a map.
55
65
*
66
+ * Constructor may be called on a background thread, as I/O and parsing may be long-running.
67
+ *
56
68
* @param map GoogleMap object
57
- * @param stream InputStream containing KML file
69
+ * @param stream InputStream containing KML or KMZ file
58
70
* @param activity Activity object
59
71
* @throws XmlPullParserException if file cannot be parsed
60
72
* @throws IOException if I/O error
@@ -67,11 +79,13 @@ public KmlLayer(GoogleMap map, InputStream stream, FragmentActivity activity)
67
79
/**
68
80
* Creates a new KmlLayer object - addLayerToMap() must be called to trigger rendering onto a map.
69
81
*
82
+ * Constructor may be called on a background thread, as I/O and parsing may be long-running.
83
+ *
70
84
* Use this constructor with shared object managers in order to handle multiple layers with
71
85
* their own event handlers on the map.
72
86
*
73
87
* @param map GoogleMap object
74
- * @param resourceId Raw resource KML file
88
+ * @param resourceId Raw resource KML or KMZ file
75
89
* @param activity Activity object
76
90
* @param markerManager marker manager to create marker collection from
77
91
* @param polygonManager polygon manager to create polygon collection from
@@ -88,11 +102,13 @@ public KmlLayer(GoogleMap map, int resourceId, FragmentActivity activity, Marker
88
102
/**
89
103
* Creates a new KmlLayer object - addLayerToMap() must be called to trigger rendering onto a map.
90
104
*
105
+ * Constructor may be called on a background thread, as I/O and parsing may be long-running.
106
+ *
91
107
* Use this constructor with shared object managers in order to handle multiple layers with
92
108
* their own event handlers on the map.
93
109
*
94
110
* @param map GoogleMap object
95
- * @param stream InputStream containing KML file
111
+ * @param stream InputStream containing KML or KMZ file
96
112
* @param activity Activity object
97
113
* @param markerManager marker manager to create marker collection from
98
114
* @param polygonManager polygon manager to create polygon collection from
@@ -106,14 +122,53 @@ public KmlLayer(GoogleMap map, InputStream stream, FragmentActivity activity, Ma
106
122
if (stream == null ) {
107
123
throw new IllegalArgumentException ("KML InputStream cannot be null" );
108
124
}
109
- KmlRenderer mRenderer = new KmlRenderer (map , activity , markerManager , polygonManager , polylineManager , groundOverlayManager );
125
+ KmlRenderer renderer = new KmlRenderer (map , activity , markerManager , polygonManager , polylineManager , groundOverlayManager );
126
+
127
+ BufferedInputStream bis = new BufferedInputStream (stream );
128
+ bis .mark (1024 );
129
+ ZipInputStream zip = new ZipInputStream (bis );
130
+ try {
131
+ KmlParser parser = null ;
132
+ ZipEntry entry = zip .getNextEntry ();
133
+ if (entry != null ) { // is a KMZ zip file
134
+ HashMap <String , Bitmap > images = new HashMap <>();
135
+ while (entry != null ) {
136
+ if (parser == null && entry .getName ().toLowerCase ().endsWith (".kml" )) {
137
+ parser = parseKml (zip );
138
+ } else {
139
+ Bitmap bitmap = BitmapFactory .decodeStream (zip );
140
+ if (bitmap != null ) {
141
+ images .put (entry .getName (), bitmap );
142
+ } else {
143
+ Log .w ("KmlLayer" , "Unsupported KMZ contents file type: " + entry .getName ());
144
+ }
145
+ }
146
+ entry = zip .getNextEntry ();
147
+ }
148
+ if (parser == null ) {
149
+ throw new IllegalArgumentException ("KML not found in InputStream" );
150
+ }
151
+ renderer .storeKmzData (parser .getStyles (), parser .getStyleMaps (), parser .getPlacemarks (),
152
+ parser .getContainers (), parser .getGroundOverlays (), images );
153
+ } else { // is a KML
154
+ bis .reset ();
155
+ parser = parseKml (bis );
156
+ renderer .storeKmlData (parser .getStyles (), parser .getStyleMaps (), parser .getPlacemarks (),
157
+ parser .getContainers (), parser .getGroundOverlays ());
158
+ }
159
+ storeRenderer (renderer );
160
+ } finally {
161
+ stream .close ();
162
+ bis .close ();
163
+ zip .close ();
164
+ }
165
+ }
166
+
167
+ private static KmlParser parseKml (InputStream stream ) throws XmlPullParserException , IOException {
110
168
XmlPullParser xmlPullParser = createXmlParser (stream );
111
169
KmlParser parser = new KmlParser (xmlPullParser );
112
170
parser .parseKml ();
113
- stream .close ();
114
- mRenderer .storeKmlData (parser .getStyles (), parser .getStyleMaps (), parser .getPlacemarks (),
115
- parser .getContainers (), parser .getGroundOverlays ());
116
- storeRenderer (mRenderer );
171
+ return parser ;
117
172
}
118
173
119
174
/**
@@ -132,7 +187,7 @@ private static XmlPullParser createXmlParser(InputStream stream) throws XmlPullP
132
187
}
133
188
134
189
/**
135
- * Adds the KML data to the map
190
+ * Adds the KML data to the map - must be called on the main UI thread
136
191
*/
137
192
@ Override
138
193
public void addLayerToMap () {
0 commit comments