diff --git a/ApiDemos/kotlin/app/build.gradle b/ApiDemos/kotlin/app/build.gradle
index da49aef1..5256777e 100644
--- a/ApiDemos/kotlin/app/build.gradle
+++ b/ApiDemos/kotlin/app/build.gradle
@@ -27,6 +27,10 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.0.2'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
+ // This dependency is needed to use RecyclerView, for the LiteListDemoActivity
+ implementation "com.android.support:recyclerview-v7:27.0.2"
+ // CardView is used in the LiteListDemoActivity
+ implementation 'com.android.support:cardview-v7:27.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
diff --git a/ApiDemos/kotlin/app/src/debug/res/values/google_maps_api.xml b/ApiDemos/kotlin/app/src/debug/res/values/google_maps_api.xml
new file mode 100644
index 00000000..e2924af4
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/debug/res/values/google_maps_api.xml
@@ -0,0 +1,17 @@
+
+
+
+ ADD_YOUR_KEY_HERE
+
+
diff --git a/ApiDemos/kotlin/app/src/main/AndroidManifest.xml b/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
index 980b5815..eb6c3e75 100644
--- a/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
+++ b/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
@@ -38,14 +38,19 @@
-
-
-
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/BasicMapDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/BasicMapDemoActivity.kt
new file mode 100644
index 00000000..b9bd3dc3
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/BasicMapDemoActivity.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.MarkerOptions
+
+/**
+ * This shows how to create a simple activity with a map and a marker on the map.
+ */
+class BasicMapDemoActivity :
+ AppCompatActivity(),
+ OnMapReadyCallback {
+
+ val SYDNEY = LatLng(-33.862, 151.21)
+ val ZOOM_LEVEL = 13f
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_basic_map_demo)
+ val mapFragment : SupportMapFragment? =
+ supportFragmentManager.findFragmentById(R.id.map) as? SupportMapFragment
+ mapFragment?.getMapAsync(this)
+ }
+
+ /**
+ * This is where we can add markers or lines, add listeners or move the camera. In this case,
+ * we just move the camera to Sydney and add a marker in Sydney.
+ */
+ override fun onMapReady(googleMap: GoogleMap?) {
+ googleMap ?: return
+ with(googleMap) {
+ moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, ZOOM_LEVEL))
+ addMarker(MarkerOptions().position(SYDNEY))
+ }
+ }
+}
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CircleDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CircleDemoActivity.kt
new file mode 100644
index 00000000..717f0b35
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CircleDemoActivity.kt
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.graphics.Color
+import android.graphics.Point
+import android.location.Location
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.view.View
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.CheckBox
+import android.widget.SeekBar
+import android.widget.Spinner
+
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.BitmapDescriptorFactory
+import com.google.android.gms.maps.model.Circle
+import com.google.android.gms.maps.model.CircleOptions
+import com.google.android.gms.maps.model.Dash
+import com.google.android.gms.maps.model.Dot
+import com.google.android.gms.maps.model.Gap
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.Marker
+import com.google.android.gms.maps.model.MarkerOptions
+import com.google.android.gms.maps.model.PatternItem
+
+import java.util.ArrayList
+import java.util.Arrays
+
+/**
+ * This shows how to draw circles on a map.
+ */
+class CircleDemoActivity :
+ AppCompatActivity(),
+ SeekBar.OnSeekBarChangeListener,
+ AdapterView.OnItemSelectedListener,
+ OnMapReadyCallback {
+
+ private val DEFAULT_RADIUS_METERS = 1000000.0
+
+ private val MAX_WIDTH_PX = 50
+ private val MAX_HUE_DEGREE = 360
+
+ private val MAX_ALPHA = 255
+ private val PATTERN_DASH_LENGTH = 100
+ private val PATTERN_GAP_LENGTH = 200
+
+ private val sydney = LatLng(-33.87365, 151.20689)
+
+ private val dot = Dot()
+ private val dash = Dash(PATTERN_DASH_LENGTH.toFloat())
+ private val gap = Gap(PATTERN_GAP_LENGTH.toFloat())
+ private val patternDotted = Arrays.asList(dot, gap)
+ private val patternDashed = Arrays.asList(dash, gap)
+ private val patternMixed = Arrays.asList(dot, gap, dot, dash, gap)
+
+ // These are the options for stroke patterns
+ private val patterns: List?>> = listOf(
+ Pair(R.string.pattern_solid, null),
+ Pair(R.string.pattern_dashed, patternDashed),
+ Pair(R.string.pattern_dotted, patternDotted),
+ Pair(R.string.pattern_mixed, patternMixed)
+ )
+
+ private lateinit var map: GoogleMap
+
+ private val circles = ArrayList(1)
+
+ private var fillColorArgb : Int = 0
+ private var strokeColorArgb: Int = 0
+
+ private lateinit var fillHueBar: SeekBar
+ private lateinit var fillAlphaBar: SeekBar
+ private lateinit var strokeWidthBar: SeekBar
+ private lateinit var strokeHueBar: SeekBar
+ private lateinit var strokeAlphaBar: SeekBar
+ private lateinit var strokePatternSpinner: Spinner
+ private lateinit var clickabilityCheckbox: CheckBox
+
+ /**
+ * This class contains information about a circle, including its markers
+ */
+ private inner class DraggableCircle(center: LatLng, private var radiusMeters: Double) {
+ private val centerMarker: Marker = map.addMarker(MarkerOptions().apply {
+ position(center)
+ draggable(true)
+ })
+
+ private val radiusMarker: Marker = map.addMarker(
+ MarkerOptions().apply {
+ position(center.getPointAtDistance(radiusMeters))
+ icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
+ draggable(true)
+ })
+
+ private val circle: Circle = map.addCircle(
+ CircleOptions().apply {
+ center(center)
+ radius(radiusMeters)
+ strokeWidth(strokeWidthBar.progress.toFloat())
+ strokeColor(strokeColorArgb)
+ fillColor(fillColorArgb)
+ clickable(clickabilityCheckbox.isChecked)
+ strokePattern(getSelectedPattern(strokePatternSpinner.selectedItemPosition))
+ })
+
+ fun onMarkerMoved(marker: Marker): Boolean {
+ when (marker) {
+ centerMarker -> {
+ circle.center = marker.position
+ radiusMarker.position = marker.position.getPointAtDistance(radiusMeters)
+ }
+ radiusMarker -> {
+ radiusMeters = centerMarker.position.distanceFrom(radiusMarker.position)
+ circle.radius = radiusMeters
+ }
+ else -> return false
+ }
+ return true
+ }
+
+ fun onStyleChange() {
+ // [circle] is treated as implicit this inside the with block
+ with(circle) {
+ strokeWidth = strokeWidthBar.progress.toFloat()
+ strokeColor = strokeColorArgb
+ fillColor = fillColorArgb
+ }
+ }
+
+ fun setStrokePattern(pattern: List?) {
+ circle.strokePattern = pattern
+ }
+
+ fun setClickable(clickable: Boolean) {
+ circle.isClickable = clickable
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_circle_demo)
+
+ // Set all the SeekBars
+ fillHueBar = findViewById(R.id.fillHueSeekBar).apply {
+ max = MAX_HUE_DEGREE
+ progress = MAX_HUE_DEGREE / 2
+ }
+ fillAlphaBar = findViewById(R.id.fillAlphaSeekBar).apply {
+ max = MAX_ALPHA
+ progress = MAX_ALPHA / 2
+ }
+ strokeWidthBar = findViewById(R.id.strokeWidthSeekBar).apply {
+ max = MAX_WIDTH_PX
+ progress = MAX_WIDTH_PX / 3
+ }
+ strokeHueBar = findViewById(R.id.strokeHueSeekBar).apply {
+ max = MAX_HUE_DEGREE
+ progress = 0
+ }
+ strokeAlphaBar = findViewById(R.id.strokeAlphaSeekBar).apply {
+ max = MAX_ALPHA
+ progress = MAX_ALPHA
+ }
+
+ strokePatternSpinner = findViewById(R.id.strokePatternSpinner).apply {
+ adapter = ArrayAdapter(this@CircleDemoActivity,
+ android.R.layout.simple_spinner_item,
+ getResourceStrings())
+ }
+
+ clickabilityCheckbox = findViewById(R.id.toggleClickability)
+
+ val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
+ mapFragment.getMapAsync(this)
+ }
+
+ /** Get all the strings of patterns and return them as Array. */
+ private fun getResourceStrings() = (patterns).map { getString(it.first) }.toTypedArray()
+
+ /**
+ * When the map is ready, move the camera to put the Circle in the middle of the screen,
+ * create a circle in Sydney, and set the listeners for the map, circles, and SeekBars.
+ */
+ override fun onMapReady(googleMap: GoogleMap?) {
+ map = googleMap ?: return
+ // we need to initialise map before creating a circle
+ with(map) {
+ moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 4.0f))
+ setContentDescription(getString(R.string.circle_demo_details))
+ setOnMapLongClickListener { point ->
+ // We know the center, let's place the outline at a point 3/4 along the view.
+ val view: View = supportFragmentManager.findFragmentById(R.id.map).view
+ ?: return@setOnMapLongClickListener
+ val radiusLatLng = map.projection.fromScreenLocation(
+ Point(view.height * 3 / 4, view.width * 3 / 4))
+ // Create the circle.
+ val newCircle = DraggableCircle(point, point.distanceFrom(radiusLatLng))
+ circles.add(newCircle)
+ }
+
+ setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
+ override fun onMarkerDragStart(marker: Marker) {
+ onMarkerMoved(marker)
+ }
+
+ override fun onMarkerDragEnd(marker: Marker) {
+ onMarkerMoved(marker)
+ }
+
+ override fun onMarkerDrag(marker: Marker) {
+ onMarkerMoved(marker)
+ }
+ })
+
+ // Flip the red, green and blue components of the circle's stroke color.
+ setOnCircleClickListener { c -> c.strokeColor = c.strokeColor xor 0x00ffffff }
+ }
+
+ fillColorArgb = Color.HSVToColor(fillAlphaBar.progress,
+ floatArrayOf(fillHueBar.progress.toFloat(), 1f, 1f))
+ strokeColorArgb = Color.HSVToColor(strokeAlphaBar.progress,
+ floatArrayOf(strokeHueBar.progress.toFloat(), 1f, 1f))
+
+ val circle = DraggableCircle(sydney, DEFAULT_RADIUS_METERS)
+ circles.add(circle)
+
+ // Set listeners for all the SeekBar
+ fillHueBar.setOnSeekBarChangeListener(this)
+ fillAlphaBar.setOnSeekBarChangeListener(this)
+
+ strokeWidthBar.setOnSeekBarChangeListener(this)
+ strokeHueBar.setOnSeekBarChangeListener(this)
+ strokeAlphaBar.setOnSeekBarChangeListener(this)
+
+ strokePatternSpinner.onItemSelectedListener = this
+ }
+
+ private fun getSelectedPattern(pos: Int): List? = patterns[pos].second
+
+ override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) {
+ if (parent.id == R.id.strokePatternSpinner) {
+ circles.map { it.setStrokePattern(getSelectedPattern(pos)) }
+ }
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>) {
+ // Don't do anything here.
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {
+ // Don't do anything here.
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {
+ // Don't do anything here.
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ // Update the fillColorArgb if the SeekBars for it is changed, otherwise keep the old value
+ fillColorArgb = when (seekBar) {
+ fillHueBar -> Color.HSVToColor(Color.alpha(fillColorArgb),
+ floatArrayOf(progress.toFloat(), 1f, 1f))
+ fillAlphaBar -> Color.argb(progress, Color.red(fillColorArgb),
+ Color.green(fillColorArgb), Color.blue(fillColorArgb))
+ else -> fillColorArgb
+ }
+
+ // Set the strokeColorArgb if the SeekBars for it is changed, otherwise keep the old value
+ strokeColorArgb = when (seekBar) {
+ strokeHueBar -> Color.HSVToColor(Color.alpha(strokeColorArgb),
+ floatArrayOf(progress.toFloat(), 1f, 1f))
+ strokeAlphaBar -> Color.argb(progress, Color.red(strokeColorArgb),
+ Color.green(strokeColorArgb), Color.blue(strokeColorArgb))
+ else -> strokeColorArgb
+ }
+
+ // Apply the style change to all the circles.
+ circles.map { it.onStyleChange() }
+ }
+
+ private fun onMarkerMoved(marker: Marker) {
+ circles.forEach { if (it.onMarkerMoved(marker)) return }
+ }
+
+ /** Listener for the Clickable CheckBox, to set if all the circles can be click */
+ fun toggleClickability(view: View) {
+ circles.map { it.setClickable((view as CheckBox).isChecked) }
+ }
+}
+
+/**
+ * Extension function to find the distance from this to another LatLng object
+ */
+private fun LatLng.distanceFrom(other: LatLng): Double {
+ val result = FloatArray(1)
+ Location.distanceBetween(latitude, longitude, other.latitude, other.longitude, result)
+ return result[0].toDouble()
+}
+
+private fun LatLng.getPointAtDistance(distance: Double): LatLng {
+ val radiusOfEarth = 6371009.0
+ val radiusAngle = (Math.toDegrees(distance / radiusOfEarth)
+ / Math.cos(Math.toRadians(latitude)))
+ return LatLng(latitude, longitude + radiusAngle)
+}
\ No newline at end of file
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CloseInfoWindowDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CloseInfoWindowDemoActivity.kt
new file mode 100644
index 00000000..f957d110
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CloseInfoWindowDemoActivity.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import com.example.kotlindemos.OnMapAndViewReadyListener.OnGlobalLayoutAndMapReadyListener
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.SupportMapFragment
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.LatLngBounds
+import com.google.android.gms.maps.model.Marker
+import com.google.android.gms.maps.model.MarkerOptions
+
+
+/**
+ * This shows how to close the info window when the currently selected marker is re-tapped.
+ */
+class CloseInfoWindowDemoActivity :
+ AppCompatActivity(),
+ OnGlobalLayoutAndMapReadyListener {
+
+ private lateinit var map: GoogleMap
+
+ /** Keeps track of the selected marker. It will be set to null if no marker is selected. */
+ private var selectedMarker: Marker? = null
+
+ /**
+ * If user tapped on the the marker which was already showing info window,
+ * the showing info window will be closed. Otherwise will show a different window.
+ */
+ private val markerClickListener = object : GoogleMap.OnMarkerClickListener {
+ override fun onMarkerClick(marker: Marker?): Boolean {
+ if (marker == selectedMarker) {
+ selectedMarker = null
+ // Return true to indicate we have consumed the event and that we do not
+ // want the the default behavior to occur (which is for the camera to move
+ // such that the marker is centered and for the marker's info window to open,
+ // if it has one).
+ return true
+ }
+
+ selectedMarker = marker
+ // Return false to indicate that we have not consumed the event and that
+ // we wish for the default behavior to occur.
+ return false
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_marker_close_info_window_on_retap_demo)
+
+ val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
+ OnMapAndViewReadyListener(mapFragment, this)
+ }
+
+ override fun onMapReady(googleMap: GoogleMap?) {
+ // Return if googleMap was null
+ map = googleMap ?: return
+
+ with(map) {
+ uiSettings.isZoomControlsEnabled = false
+
+ setOnMarkerClickListener(markerClickListener)
+
+ // Set listener for map click event. Any showing info window closes
+ // when the map is clicked. Clear the currently selected marker.
+ setOnMapClickListener { selectedMarker = null }
+
+ setContentDescription(getString(R.string.close_info_window_demo_details))
+
+ // Add markers to different cities in Australia and include it in bounds
+ val bounds = LatLngBounds.Builder()
+ cities.map { city ->
+ addMarker(MarkerOptions().apply {
+ position(city.latLng)
+ title(city.title)
+ snippet(city.snippet)
+ })
+ bounds.include(city.latLng)
+ }
+
+ moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 50))
+ }
+ }
+
+ /**
+ * Class to contain information about a marker.
+ *
+ * @property latLng latitude and longitude of the marker
+ * @property title a string containing the city name
+ * @property snippet a string containing the population of the city
+ */
+ class MarkerInfo(val latLng: LatLng, val title: String, val snippet: String)
+
+ private val cities = listOf(
+ MarkerInfo(LatLng(-27.47093, 153.0235),
+ "Brisbane", "Population: 2,074,200"),
+ MarkerInfo(LatLng(-37.81319, 144.96298),
+ "Melbourne", "Population: 4,137,400"),
+ MarkerInfo(LatLng(-33.87365, 151.20689),
+ "Sydney", "Population: 4,627,300"),
+ MarkerInfo(LatLng(-34.92873, 138.59995),
+ "Adelaide", "Population: 1,213,000"),
+ MarkerInfo(LatLng(-31.952854, 115.857342),
+ "Perth", "Population: 1,738,800")
+ )
+}
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/DemoDetailsList.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/DemoDetailsList.kt
index 123ad938..0977c99b 100644
--- a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/DemoDetailsList.kt
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/DemoDetailsList.kt
@@ -22,18 +22,33 @@ package com.example.kotlindemos
class DemoDetailsList {
companion object {
val DEMOS = listOf(
- DemoDetails(R.string.polygon_demo_label, R.string.polygon_demo_details,
- PolygonDemoActivity::class.java),
+ DemoDetails(R.string.basic_demo_label, R.string.basic_demo_details,
+ BasicMapDemoActivity::class.java),
DemoDetails(R.string.camera_demo_label, R.string.camera_demo_description,
CameraDemoActivity::class.java),
- DemoDetails(R.string.markers_demo_label, R.string.markers_demo_description,
- MarkerDemoActivity::class.java),
+ DemoDetails(R.string.circle_demo_label, R.string.circle_demo_details,
+ CircleDemoActivity::class.java),
+ DemoDetails(R.string.close_info_window_demo_label,
+ R.string.close_info_window_demo_details,
+ CloseInfoWindowDemoActivity::class.java),
DemoDetails(R.string.layers_demo_label, R.string.layers_demo_description,
LayersDemoActivity::class.java),
+ DemoDetails(R.string.lite_list_demo_label, R.string.lite_list_demo_details,
+ LiteListDemoActivity::class.java),
+ DemoDetails(R.string.markers_demo_label, R.string.markers_demo_description,
+ MarkerDemoActivity::class.java),
+ DemoDetails(R.string.polygon_demo_label, R.string.polygon_demo_details,
+ PolygonDemoActivity::class.java),
DemoDetails(R.string.polyline_demo_label, R.string.polyline_demo_description,
PolylineDemoActivity::class.java),
+ DemoDetails(
+ R.string.street_view_panorama_navigation_demo_label,
+ R.string.street_view_panorama_navigation_demo_details,
+ StreetViewPanoramaNavigationDemoActivity::class.java),
DemoDetails(R.string.tags_demo_label, R.string.tags_demo_details,
TagsDemoActivity::class.java),
+ DemoDetails(R.string.ui_settings_demo_label, R.string.ui_settings_demo_details,
+ UiSettingsDemoActivity::class.java),
DemoDetails(R.string.region_demo_label, R.string.region_demo_details,
VisibleRegionDemoActivity::class.java)
)
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt
new file mode 100644
index 00000000..a9f02e49
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/LiteListDemoActivity.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import com.google.android.gms.maps.CameraUpdateFactory
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.MapsInitializer
+import com.google.android.gms.maps.MapView
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.MarkerOptions
+
+/**
+ * This shows to include a map in lite mode in a RecyclerView.
+ * Note the use of the view holder pattern with the
+ * [com.google.android.gms.maps.OnMapReadyCallback].
+ */
+class LiteListDemoActivity : AppCompatActivity() {
+
+ private val linearLayoutManager: LinearLayoutManager by lazy {
+ LinearLayoutManager(this)
+ }
+
+ private val gridLayoutManager: GridLayoutManager by lazy {
+ GridLayoutManager(this, 2)
+ }
+
+ private lateinit var recyclerView: RecyclerView
+ private lateinit var mapAdapter: RecyclerView.Adapter
+
+ /**
+ * RecycleListener that completely clears the [com.google.android.gms.maps.GoogleMap]
+ * attached to a row in the RecyclerView.
+ * Sets the map type to [com.google.android.gms.maps.GoogleMap.MAP_TYPE_NONE] and clears
+ * the map.
+ */
+ private val recycleListener = RecyclerView.RecyclerListener { holder ->
+ val mapHolder = holder as MapAdapter.ViewHolder
+ mapHolder.clearView()
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_lite_list_demo)
+
+ mapAdapter = MapAdapter()
+
+ // Initialise the RecyclerView.
+ recyclerView = findViewById(R.id.recycler_view).apply {
+ setHasFixedSize(true)
+ layoutManager = linearLayoutManager
+ adapter = mapAdapter
+ setRecyclerListener(recycleListener)
+ }
+ }
+
+ /** Create options menu to switch between the linear and grid layout managers. */
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.lite_list_menu, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+ recyclerView.layoutManager = when (item?.itemId) {
+ R.id.layout_linear -> linearLayoutManager
+ R.id.layout_grid -> gridLayoutManager
+ else -> return false
+ }
+ return true
+ }
+
+ /**
+ * Adapter that displays a title and [com.google.android.gms.maps.MapView] for each item.
+ * The layout is defined in `lite_list_demo_row.xml`. It contains a MapView
+ * that is programatically initialised when onCreateViewHolder is called.
+ */
+ inner class MapAdapter : RecyclerView.Adapter() {
+
+ override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
+ holder?.bindView(position) ?: return
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflated = LayoutInflater.from(parent.context)
+ .inflate(R.layout.lite_list_demo_row, parent, false)
+ return ViewHolder(inflated)
+ }
+
+ override fun getItemCount() = listLocations.size
+
+ /** A view holder for the map and title. */
+ inner class ViewHolder(view: View) :
+ RecyclerView.ViewHolder(view),
+ OnMapReadyCallback {
+
+ private val layout: View = view
+ private val mapView: MapView = layout.findViewById(R.id.lite_listrow_map)
+ private val title: TextView = layout.findViewById(R.id.lite_listrow_text)
+ private lateinit var map: GoogleMap
+ private lateinit var latLng: LatLng
+
+ /** Initialises the MapView by calling its lifecycle methods */
+ init {
+ with(mapView) {
+ // Initialise the MapView
+ onCreate(null)
+ // Set the map ready callback to receive the GoogleMap object
+ getMapAsync(this@ViewHolder)
+ }
+ }
+
+ private fun setMapLocation() {
+ if (!::map.isInitialized) return
+ with(map) {
+ moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13f))
+ addMarker(MarkerOptions().position(latLng))
+ mapType = GoogleMap.MAP_TYPE_NORMAL
+ setOnMapClickListener {
+ Toast.makeText(this@LiteListDemoActivity, "Clicked on ${title.text}",
+ Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ override fun onMapReady(googleMap: GoogleMap?) {
+ MapsInitializer.initialize(applicationContext)
+ // If map is not initialised properly
+ map = googleMap ?: return
+ setMapLocation()
+ }
+
+ /** This function is called when the RecyclerView wants to bind the ViewHolder. */
+ fun bindView(position: Int) {
+ listLocations[position].let {
+ latLng = it.second
+ mapView.tag = this
+ title.text = it.first
+ // We need to call setMapLocation from here because RecyclerView might use the
+ // previously loaded maps
+ setMapLocation()
+ }
+ }
+
+ /** This function is called by the recycleListener, when we need to clear the map. */
+ fun clearView() {
+ with(map) {
+ // Clear the map and free up resources by changing the map type to none
+ clear()
+ mapType = GoogleMap.MAP_TYPE_NONE
+ }
+ }
+ }
+ }
+
+ /** A list of locations of to show in the RecyclerView */
+ private val listLocations: List> = listOf(
+ Pair("Cape Town", LatLng(-33.920455, 18.466941)),
+ Pair("Beijing", LatLng(39.937795, 116.387224)),
+ Pair("Bern", LatLng(46.948020, 7.448206)),
+ Pair("Breda", LatLng(51.589256, 4.774396)),
+ Pair("Brussels", LatLng(50.854509, 4.376678)),
+ Pair("Copenhagen", LatLng(55.679423, 12.577114)),
+ Pair("Hannover", LatLng(52.372026, 9.735672)),
+ Pair("Helsinki", LatLng(60.169653, 24.939480)),
+ Pair("Hong Kong", LatLng(22.325862, 114.165532)),
+ Pair("Istanbul", LatLng(41.034435, 28.977556)),
+ Pair("Johannesburg", LatLng(-26.202886, 28.039753)),
+ Pair("Lisbon", LatLng(38.707163, -9.135517)),
+ Pair("London", LatLng(51.500208, -0.126729)),
+ Pair("Madrid", LatLng(40.420006, -3.709924)),
+ Pair("Mexico City", LatLng(19.427050, -99.127571)),
+ Pair("Moscow", LatLng(55.750449, 37.621136)),
+ Pair("New York", LatLng(40.750580, -73.993584)),
+ Pair("Oslo", LatLng(59.910761, 10.749092)),
+ Pair("Paris", LatLng(48.859972, 2.340260)),
+ Pair("Prague", LatLng(50.087811, 14.420460)),
+ Pair("Rio de Janeiro", LatLng(-22.90187, -43.232437)),
+ Pair("Rome", LatLng(41.889998, 12.500162)),
+ Pair("Sao Paolo", LatLng(-22.863878, -43.244097)),
+ Pair("Seoul", LatLng(37.560908, 126.987705)),
+ Pair("Stockholm", LatLng(59.330650, 18.067360)),
+ Pair("Sydney", LatLng(-33.873651, 151.2068896)),
+ Pair("Taipei", LatLng(25.022112, 121.478019)),
+ Pair("Tokyo", LatLng(35.670267, 139.769955)),
+ Pair("Tulsa Oklahoma", LatLng(36.149777, -95.993398)),
+ Pair("Vaduz", LatLng(47.141076, 9.521482)),
+ Pair("Vienna", LatLng(48.209206, 16.372778)),
+ Pair("Warsaw", LatLng(52.235474, 21.004057)),
+ Pair("Wellington", LatLng(-41.286480, 174.776217)),
+ Pair("Winnipeg", LatLng(49.875832, -97.150726))
+ )
+}
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MainActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MainActivity.kt
index 4ead271d..ad93c28a 100644
--- a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MainActivity.kt
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MainActivity.kt
@@ -61,8 +61,8 @@ class MainActivity : AppCompatActivity(), AdapterView.OnItemClickListener {
class CustomArrayAdapter(context: Context, demos: List) :
ArrayAdapter(context, R.id.title, demos) {
- override fun getView(position: Int, convertView: View?, parent: ViewGroup) : View {
- val demo : DemoDetails = getItem(position)
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+ val demo: DemoDetails = getItem(position)
return (convertView as? FeatureView ?: FeatureView(context)).apply {
setTitleId(demo.titleId)
setDescriptionId(demo.descriptionId)
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
index 0af23bba..314f46c5 100644
--- a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/OnMapAndViewReadyListener.kt
@@ -73,6 +73,7 @@ class OnMapAndViewReadyListener(
}
// We use the new method when supported
+ @Suppress("DEPRECATION")
@SuppressLint("NewApi") // We check which build version we are using.
override fun onGlobalLayout() {
// Remove our listener.
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt
new file mode 100644
index 00000000..f66e5418
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/StreetViewPanoramaNavigationDemoActivity.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.view.View
+import android.widget.SeekBar
+import android.widget.Toast
+import com.google.android.gms.maps.StreetViewPanorama
+import com.google.android.gms.maps.SupportStreetViewPanoramaFragment
+import com.google.android.gms.maps.model.LatLng
+import com.google.android.gms.maps.model.StreetViewPanoramaCamera
+import com.google.android.gms.maps.model.StreetViewPanoramaLink
+
+/**
+ * This shows how to create an activity with access to all the options in Panorama
+ * which can be adjusted dynamically.
+ */
+class StreetViewPanoramaNavigationDemoActivity : AppCompatActivity() {
+
+ // George St, Sydney
+ private val sydney = LatLng(-33.87365, 151.20689)
+ // Cole St, San Francisco
+ private val sanFrancisco = LatLng(37.769263, -122.450727)
+ // Santorini, Greece using the Pano ID of the location instead of a LatLng object
+ private val santoriniPanoId = "WddsUw1geEoAAAQIt9RnsQ"
+ // LatLng with no panorama
+ private val invalid = LatLng(-45.125783, 151.276417)
+
+ // The amount in degrees by which to scroll the camera
+ private val PAN_BY_DEGREES = 30
+ // The amount of zoom
+ private val ZOOM_BY = 0.5f
+
+ private lateinit var streetViewPanorama: StreetViewPanorama
+ private lateinit var customDurationBar: SeekBar
+
+ private val duration: Long
+ get() = customDurationBar.progress.toLong()
+
+ override fun onCreate(savedInstanceState:Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_street_view_panorama_navigation_demo)
+
+ val streetViewPanoramaFragment = supportFragmentManager
+ .findFragmentById(R.id.streetviewpanorama) as SupportStreetViewPanoramaFragment
+ streetViewPanoramaFragment.getStreetViewPanoramaAsync { panorama ->
+ streetViewPanorama = panorama
+ // Only set the panorama to sydney on startup (when no panoramas have been
+ // loaded which is when the savedInstanceState is null).
+ if (savedInstanceState == null) {
+ streetViewPanorama.setPosition(sydney)
+ }
+ }
+
+ customDurationBar = findViewById(R.id.duration_bar)
+ }
+
+ /**
+ * Checks if the map is ready, the executes the provided lamdba function
+ *
+ * @param stuffToDo the code to be executed if [streetViewPanorama] is ready
+ */
+ private fun checkReadyThen(stuffToDo : () -> Unit) {
+ if (!::streetViewPanorama.isInitialized) {
+ Toast.makeText(this, R.string.map_not_ready, Toast.LENGTH_SHORT).show()
+ } else {
+ stuffToDo()
+ }
+ }
+
+ /**
+ * Called when the Go To Location button is pressed
+ */
+ fun onGoToLocation(view: View) {
+ when (view.id) {
+ R.id.sydney -> streetViewPanorama.setPosition(sydney)
+ R.id.sanfrancisco -> streetViewPanorama.setPosition(sanFrancisco)
+ R.id.santorini -> streetViewPanorama.setPosition(santoriniPanoId)
+ R.id.invalid -> streetViewPanorama.setPosition(invalid)
+ }
+ }
+
+ /**
+ * This function is called from the listeners, and builds the street view panorama with the
+ * specified arguments.
+ */
+ private fun updateStreetViewPanorama(zoom: Float, tilt: Float, bearing: Float) {
+ streetViewPanorama.animateTo(StreetViewPanoramaCamera.Builder().apply {
+ zoom(zoom)
+ tilt(tilt)
+ bearing(bearing)
+ } .build(), duration)
+ }
+
+ fun onButtonClicked(view: View) {
+ checkReadyThen {
+ with(streetViewPanorama.panoramaCamera) {
+ when (view.id) {
+ R.id.zoom_in -> updateStreetViewPanorama(zoom + ZOOM_BY, tilt, bearing)
+ R.id.zoom_out -> updateStreetViewPanorama(zoom - ZOOM_BY, tilt, bearing)
+ R.id.pan_left -> updateStreetViewPanorama(zoom, tilt, bearing - PAN_BY_DEGREES)
+ R.id.pan_right -> updateStreetViewPanorama(zoom, tilt, bearing + PAN_BY_DEGREES)
+ R.id.pan_up -> {
+ var newTilt = tilt + PAN_BY_DEGREES
+ if (newTilt > 90) newTilt = 90f
+ updateStreetViewPanorama(zoom, newTilt, bearing)
+ }
+ R.id.pan_down -> {
+ var newTilt = tilt - PAN_BY_DEGREES
+ if (newTilt < -90) newTilt = -90f
+ updateStreetViewPanorama(zoom, newTilt, bearing)
+ }
+ }
+ }
+ }
+ }
+
+ fun onRequestPosition(view: View) {
+ checkReadyThen {
+ streetViewPanorama.location?.let {
+ Toast.makeText(view.context, streetViewPanorama.location.position.toString(),
+ Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onMovePosition(view: View) {
+ val location = streetViewPanorama.location
+ val camera = streetViewPanorama.panoramaCamera
+ location?.links?.let {
+ val link = location.links.findClosestLinkToBearing(camera.bearing)
+ streetViewPanorama.setPosition(link.panoId)
+ }
+ }
+
+ /** Extension function to find the closest link from a point. */
+ private fun Array.findClosestLinkToBearing(
+ bearing: Float
+ ): StreetViewPanoramaLink {
+
+ // Find the difference between angle a and b as a value between 0 and 180.
+ val findNormalizedDifference = fun (a: Float, b: Float): Float {
+ val diff = a - b
+ val normalizedDiff = diff - (360 * Math.floor((diff / 360.0f).toDouble())).toFloat()
+ return if ((normalizedDiff < 180.0f)) normalizedDiff else 360.0f - normalizedDiff
+ }
+
+ var minBearingDiff = 360f
+ var closestLink = this[0]
+ for (link in this) {
+ if (minBearingDiff > findNormalizedDifference(bearing, link.bearing)) {
+ minBearingDiff = findNormalizedDifference(bearing, link.bearing)
+ closestLink = link
+ }
+ }
+ return closestLink
+ }
+}
diff --git a/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/UiSettingsDemoActivity.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/UiSettingsDemoActivity.kt
new file mode 100644
index 00000000..ad079285
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/UiSettingsDemoActivity.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.kotlindemos
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.view.View
+import android.widget.CheckBox
+import com.google.android.gms.maps.GoogleMap
+import com.google.android.gms.maps.OnMapReadyCallback
+import com.google.android.gms.maps.SupportMapFragment
+import pub.devrel.easypermissions.AfterPermissionGranted
+import pub.devrel.easypermissions.EasyPermissions
+
+const val REQUEST_CODE_LOCATION = 123
+
+class UiSettingsDemoActivity :
+ AppCompatActivity(),
+ OnMapReadyCallback {
+
+ private lateinit var map: GoogleMap
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_ui_settings_demo)
+ val mapFragment: SupportMapFragment =
+ supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
+ mapFragment.getMapAsync(this)
+ }
+
+ override fun onMapReady(googleMap: GoogleMap?) {
+ // Return early if map is not initialised properly
+ map = googleMap ?: return
+ enableMyLocation()
+ // Set all the settings of the map to match the current state of the checkboxes
+ with(map.uiSettings) {
+ isZoomControlsEnabled = isChecked(R.id.zoom_button)
+ isCompassEnabled = isChecked(R.id.compass_button)
+ isMyLocationButtonEnabled = isChecked(R.id.myloc_button)
+ isIndoorLevelPickerEnabled = isChecked(R.id.level_button)
+ isMapToolbarEnabled = isChecked(R.id.maptoolbar_button)
+ isZoomGesturesEnabled = isChecked(R.id.zoomgest_button)
+ isScrollGesturesEnabled = isChecked(R.id.scrollgest_button)
+ isTiltGesturesEnabled = isChecked(R.id.tiltgest_button)
+ isRotateGesturesEnabled = isChecked(R.id.rotategest_button)
+ }
+ }
+
+ /** On click listener for checkboxes */
+ fun onClick(view: View) {
+ if (view !is CheckBox) {
+ return
+ }
+ val isChecked: Boolean = view.isChecked
+ with(map.uiSettings) {
+ when (view.id) {
+ R.id.zoom_button -> isZoomControlsEnabled = isChecked
+ R.id.compass_button -> isCompassEnabled = isChecked
+ R.id.myloc_button -> isMyLocationButtonEnabled = isChecked
+ R.id.level_button -> isIndoorLevelPickerEnabled = isChecked
+ R.id.maptoolbar_button -> isMapToolbarEnabled = isChecked
+ R.id.zoomgest_button -> isZoomGesturesEnabled = isChecked
+ R.id.scrollgest_button -> isScrollGesturesEnabled = isChecked
+ R.id.tiltgest_button -> isTiltGesturesEnabled = isChecked
+ R.id.rotategest_button -> isRotateGesturesEnabled = isChecked
+ }
+ }
+ }
+
+ /** Returns whether the checkbox with the given id is checked */
+ private fun isChecked(id: Int) = findViewById(id)?.isChecked ?: false
+
+ /** Override the onRequestPermissionResult to use EasyPermissions */
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
+ }
+
+ /**
+ * enableMyLocation() will enable the location of the map if the user has given permission
+ * for the app to access their device location.
+ * Android Studio requires an explicit check before setting map.isMyLocationEnabled to true
+ * but we are using EasyPermissions to handle it so we can suppress the "MissingPermission"
+ * check.
+ */
+ @SuppressLint("MissingPermission")
+ @AfterPermissionGranted(REQUEST_CODE_LOCATION)
+ private fun enableMyLocation() {
+ if (hasLocationPermission()) {
+ map.isMyLocationEnabled = true
+ } else {
+ EasyPermissions.requestPermissions(this, getString(R.string.location),
+ REQUEST_CODE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ }
+ }
+
+ private fun hasLocationPermission(): Boolean {
+ return EasyPermissions.hasPermissions(this, Manifest.permission.ACCESS_FINE_LOCATION)
+ }
+}
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_basic_map_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_basic_map_demo.xml
new file mode 100644
index 00000000..17225bd4
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_basic_map_demo.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_circle_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_circle_demo.xml
new file mode 100644
index 00000000..6b7c3c91
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_circle_demo.xml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_lite_list_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_lite_list_demo.xml
new file mode 100644
index 00000000..949d8ebf
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_lite_list_demo.xml
@@ -0,0 +1,22 @@
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_marker_close_info_window_on_retap_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_marker_close_info_window_on_retap_demo.xml
new file mode 100644
index 00000000..027d9c8f
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_marker_close_info_window_on_retap_demo.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_street_view_panorama_navigation_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_street_view_panorama_navigation_demo.xml
new file mode 100644
index 00000000..58f7425b
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_street_view_panorama_navigation_demo.xml
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/activity_ui_settings_demo.xml b/ApiDemos/kotlin/app/src/main/res/layout/activity_ui_settings_demo.xml
new file mode 100644
index 00000000..23bb84a6
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/activity_ui_settings_demo.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ApiDemos/kotlin/app/src/main/res/layout/lite_list_demo_row.xml b/ApiDemos/kotlin/app/src/main/res/layout/lite_list_demo_row.xml
new file mode 100644
index 00000000..bb4c56ab
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/layout/lite_list_demo_row.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ApiDemos/kotlin/app/src/main/res/menu/lite_list_menu.xml b/ApiDemos/kotlin/app/src/main/res/menu/lite_list_menu.xml
new file mode 100644
index 00000000..8da00b94
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/res/menu/lite_list_menu.xml
@@ -0,0 +1,30 @@
+
+
+
\ No newline at end of file
diff --git a/ApiDemos/kotlin/app/src/main/res/values/strings.xml b/ApiDemos/kotlin/app/src/main/res/values/strings.xml
index 053076be..cc45be76 100644
--- a/ApiDemos/kotlin/app/src/main/res/values/strings.xml
+++ b/ApiDemos/kotlin/app/src/main/res/values/strings.xml
@@ -19,6 +19,10 @@
No demosGoogle Play services is not installed on this device.
+
+ Basic Map
+ Launches a map with marker pointing at Sydney.
+
AnimateDemonstrates Camera Functions
@@ -36,48 +40,14 @@
+-
-
- Tags
- Demonstrates how to get and set tags on API objects.
- Map with a circle, ground overlay, marker, polygon and polyline.
+
+ Circle Demo
+ Demonstrate how to add circles to a map
+ Properties for Circle(s)
-
- Clickable
- Fill Alpha
- Fill Hue
- Bevel
- Default
- Round
- Dashed
- Dotted
- Mixed
- Solid
- Demonstrates how to add Polygons to a map.
- Demonstrates how to add Polygons to a map
- Polygons
- Properties for Polygon over Australia
- Stroke Alpha
- Stroke Hue
- Stroke Joint Type
- Stroke Pattern
- Stroke Width
-
-
- Custom Info Contents
- Custom Info Window
- Default Info Window
- Drag Melbourne
- Clear
- Flat
- Reset
- Map is not ready
- Demonstrates how to add Markers to a map.
- Markers
- onMarkerDrag. Current Position: (%1$f, %2$f)
- Started dragging marker
- Marker stopped dragging
- Rotation
- State badge
+
+ Close Info Window Demo
+ Demonstrates how to close the info window when the currently selected marker is retapped.Buildings
@@ -100,11 +70,55 @@
TerrainTraffic
+
+ Lite List Demo
+ Show a list of Lite Map of different locations using RecyclerView with LinearLayoutManager and GridLayoutManager
+ Linear
+ Grid
+
+
+ Custom Info Contents
+ Custom Info Window
+ Default Info Window
+ Drag Melbourne
+ Clear
+ Flat
+ Reset
+ Map is not ready
+ Demonstrates how to add Markers to a map.
+ Markers
+ onMarkerDrag. Current Position: (%1$f, %2$f)
+ Started dragging marker
+ Marker stopped dragging
+ Rotation
+ State badge
+
Access to the location service is required to demonstrate the \'my location\' feature, which shows your current location on the map.This sample requires location permission to enable the \'my location\' layer. Please try again and grant access to use the location.\nIf the permission has been permanently denied, it can be enabled from the System Settings > Apps > \'Google Maps API Demos\'.Location permission is required for this demo.
+
+ Clickable
+ Fill Alpha
+ Fill Hue
+ Bevel
+ Default
+ Round
+ Dashed
+ Dotted
+ Mixed
+ Solid
+ Demonstrates how to add Polygons to a map.
+ Demonstrates how to add Polygons to a map
+ Polygons
+ Properties for Polygon over Australia
+ Stroke Alpha
+ Stroke Hue
+ Stroke Joint Type
+ Stroke Pattern
+ Stroke Width
+
AlphaButt
@@ -120,6 +134,34 @@
Start CapWidth
+
+ Street View Panorama Navigation Demo
+ Street View Panorama with programmatic navigation
+ Position
+ Walk
+ Go to Invalid Point
+ Go to San Francisco
+ Go to Santorini
+
+
+ Tags
+ Demonstrates how to get and set tags on API objects.
+ Map with a circle, ground overlay, marker, polygon and polyline.
+
+
+ UI Settings Demo
+ Demonstrate how to toggle the UI of a map
+ Location permission is required to run the demo
+ Zoom
+ Compass
+ My Location
+ Level Picker
+ Map Toolbar
+ Zoom Gestures
+ Scroll Gestures
+ Tilt Gestures
+ Rotate Gestures
+
CameraChangeListener: %1$sVisible Regions