diff --git a/ApiDemos/kotlin/app/src/main/AndroidManifest.xml b/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
index 554fb6d9..00e56083 100644
--- a/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
+++ b/ApiDemos/kotlin/app/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
+
@@ -34,7 +35,8 @@
-
+
+
\ No newline at end of file
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..d89851e8
--- /dev/null
+++ b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/CircleDemoActivity.kt
@@ -0,0 +1,322 @@
+/*
+ * 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() {
+ 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 as View
+ 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
+ }
+
+ 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/DemoDetailsList.kt b/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/DemoDetailsList.kt
index 0d71a3b1..0e7600d3 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
@@ -23,7 +23,9 @@ class DemoDetailsList {
companion object {
val DEMOS = listOf(
DemoDetails(R.string.basic_demo_label, R.string.basic_demo_details,
- BasicMapDemoActivity::class.java)
+ BasicMapDemoActivity::class.java),
+ DemoDetails(R.string.circle_demo_label, R.string.circle_demo_details,
+ CircleDemoActivity::class.java)
)
}
}
\ No newline at end of file
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/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/values/strings.xml b/ApiDemos/kotlin/app/src/main/res/values/strings.xml
index 918ce5be..d49a8ecd 100644
--- a/ApiDemos/kotlin/app/src/main/res/values/strings.xml
+++ b/ApiDemos/kotlin/app/src/main/res/values/strings.xml
@@ -23,4 +23,29 @@
Basic Map
Launches a map with marker pointing at Sydney
+
+ 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
\ No newline at end of file