Merge branch 'kotlin-samples'

This commit is contained in:
Bella Mangunsong 2018-02-12 16:04:58 +11:00
commit e041f1827b
21 changed files with 1712 additions and 3 deletions

View File

@ -27,8 +27,16 @@ 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'
implementation 'com.google.android.gms:play-services-maps:11.8.0'
compile 'com.google.android.gms:play-services-location:11.8.0'
// EasyPermissions is needed to help us request for permission to access location
implementation 'pub.devrel:easypermissions:1.1.1'
}

View File

@ -0,0 +1,17 @@
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API key.
See this page for more information:
https://developers.google.com/maps/documentation/android/start#get_an_android_certificate_and_the_google_maps_api_key
Once you have your key (it starts with "AIza"), replace the "google_maps_key"
string in this file.
Note: This resource is used for the debug build target. Update this file if you just want to run
the demo app.
-->
<string name="google_maps_key" translatable="false" templateMergeStrategy="preserve">
ADD_YOUR_KEY_HERE
</string>
</resources>

View File

@ -16,6 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.kotlindemos">
<!-- Access to location is needed for the UI Settings Demo -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
@ -23,6 +26,11 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -30,6 +38,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".BasicMapDemoActivity" />
<activity android:name=".CircleDemoActivity" />
<activity android:name=".CloseInfoWindowDemoActivity" />
<activity android:name=".LiteListDemoActivity" />
<activity android:name=".StreetViewPanoramaNavigationDemoActivity" />
<activity android:name=".UiSettingsDemoActivity" />
</application>
</manifest>

View File

@ -0,0 +1,57 @@
/*
* 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) {
with(googleMap) {
moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, ZOOM_LEVEL))
addMarker(MarkerOptions().position(SYDNEY))
}
}
}

View File

@ -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<Pair<Int, List<PatternItem>?>> = 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<DraggableCircle>(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<PatternItem>?) {
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<SeekBar>(R.id.fillHueSeekBar).apply {
max = MAX_HUE_DEGREE
progress = MAX_HUE_DEGREE / 2
}
fillAlphaBar = findViewById<SeekBar>(R.id.fillAlphaSeekBar).apply {
max = MAX_ALPHA
progress = MAX_ALPHA / 2
}
strokeWidthBar = findViewById<SeekBar>(R.id.strokeWidthSeekBar).apply {
max = MAX_WIDTH_PX
progress = MAX_WIDTH_PX / 3
}
strokeHueBar = findViewById<SeekBar>(R.id.strokeHueSeekBar).apply {
max = MAX_HUE_DEGREE
progress = 0
}
strokeAlphaBar = findViewById<SeekBar>(R.id.strokeAlphaSeekBar).apply {
max = MAX_ALPHA
progress = MAX_ALPHA
}
strokePatternSpinner = findViewById<Spinner>(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<PatternItem>? = 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)
}

View File

@ -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")
)
}

View File

@ -21,6 +21,22 @@ package com.example.kotlindemos
*/
class DemoDetailsList {
companion object {
val DEMOS = listOf<DemoDetails>()
val DEMOS = listOf<DemoDetails>(
DemoDetails(R.string.basic_demo_label, R.string.basic_demo_details,
BasicMapDemoActivity::class.java),
DemoDetails(R.string.close_info_window_demo_label,
R.string.close_info_window_demo_details,
CloseInfoWindowDemoActivity::class.java),
DemoDetails(R.string.circle_demo_label, R.string.circle_demo_details,
CircleDemoActivity::class.java),
DemoDetails(R.string.lite_list_demo_label, R.string.lite_list_demo_details,
LiteListDemoActivity::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.ui_settings_demo_label, R.string.ui_settings_demo_details,
UiSettingsDemoActivity::class.java)
)
}
}

View File

@ -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<MapAdapter.ViewHolder>
/**
* 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<RecyclerView>(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<MapAdapter.ViewHolder>() {
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<Pair<String, LatLng>> = 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))
)
}

View File

@ -61,8 +61,8 @@ class MainActivity : AppCompatActivity(), AdapterView.OnItemClickListener {
class CustomArrayAdapter(context: Context, demos: List<DemoDetails>) :
ArrayAdapter<DemoDetails>(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)

View File

@ -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<StreetViewPanoramaLink>.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
}
}

View File

@ -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.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<CheckBox>(id)?.isChecked ?: false
/** Override the onRequestPermissionResult to use EasyPermissions */
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
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)
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.kotlindemos.BasicMapDemoActivity">
</fragment>

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/properties_circle" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView android:text="@string/fill_hue" />
<SeekBar android:id="@+id/fillHueSeekBar" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView android:text="@string/fill_alpha" />
<SeekBar android:id="@+id/fillAlphaSeekBar" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView android:text="@string/stroke_width" />
<SeekBar android:id="@+id/strokeWidthSeekBar" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView android:text="@string/stroke_hue" />
<SeekBar android:id="@+id/strokeHueSeekBar" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView android:text="@string/stroke_alpha" />
<SeekBar android:id="@+id/strokeAlphaSeekBar" />
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:text="@string/stroke_pattern"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Spinner
android:id="@+id/strokePatternSpinner"
android:spinnerMode="dropdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<CheckBox
android:id="@+id/toggleClickability"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:onClick="toggleClickability"
android:text="@string/clickable"/>
</TableRow>
</TableLayout>
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android" />

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>

View File

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/get_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onRequestPosition"
android:text="@string/request_position" />
<Button
android:id="@+id/move_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onMovePosition"
android:text="@string/walk_panorama" />
</LinearLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:layout_weight="1">
<Button
android:id="@+id/pan_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:text="@string/left_arrow"
android:layout_alignParentStart="true" />
<Button
android:id="@+id/pan_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/pan_left"
android:text="@string/up_arrow"
android:layout_toEndOf="@id/pan_left" />
<Button
android:id="@+id/pan_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:layout_below="@id/pan_up"
android:layout_toRightOf="@id/pan_left"
android:text="@string/down_arrow"
android:layout_toEndOf="@id/pan_left" />
<Button
android:id="@+id/pan_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/pan_down"
android:text="@string/right_arrow"
android:layout_toEndOf="@id/pan_down" />
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="vertical">
<Button
android:id="@+id/zoom_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:text="@string/zoom_in" />
<Button
android:id="@+id/zoom_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:onClick="onButtonClicked"
android:text="@string/zoom_out" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/duration" />
<SeekBar
android:id="@+id/duration_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:progress="1000"
android:max="5000" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/sydney"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:onClick="onGoToLocation"
android:layout_weight="1"
android:text="@string/go_to_sydney"
style="?android:attr/borderlessButtonStyle" />
<Button
android:id="@+id/sanfrancisco"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:onClick="onGoToLocation"
android:layout_weight="1"
android:text="@string/go_to_san_francisco"
style="?android:attr/borderlessButtonStyle" />
<Button
android:id="@+id/santorini"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:onClick="onGoToLocation"
android:layout_weight="1"
android:text="@string/go_to_santorini"
style="?android:attr/borderlessButtonStyle" />
<Button
android:id="@+id/invalid"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:onClick="onGoToLocation"
android:layout_weight="1"
android:text="@string/go_to_invalid"
style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
<fragment
android:id="@+id/streetviewpanorama"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.google.android.gms.maps.SupportStreetViewPanoramaFragment" />
</LinearLayout>

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="175dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="25dp"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<CheckBox
android:id="@+id/zoom_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_zoom" />
<CheckBox
android:id="@+id/compass_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_compass" />
<CheckBox
android:id="@+id/myloc_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_my_location_layer" />
<CheckBox
android:id="@+id/level_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_level_picker" />
<CheckBox
android:id="@+id/maptoolbar_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_map_toolbar" />
<CheckBox
android:id="@+id/zoomgest_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_zoom_gesture" />
<CheckBox
android:id="@+id/scrollgest_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_scroll_gesture" />
<CheckBox
android:id="@+id/tiltgest_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_tilt_gesture" />
<CheckBox
android:id="@+id/rotategest_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/checkbox_rotate_gesture" />
</LinearLayout>
</ScrollView>
</RelativeLayout>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="5dp">
<!-- Put the name of the location and the map inside a CardView -->
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
card_view:cardCornerRadius="0dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/lite_listrow_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentTop="true"/>
<!-- MapView in lite mode. Note that it needs to be initialised
programmatically before it can be used. -->
<com.google.android.gms.maps.MapView
android:id="@+id/lite_listrow_map"
android:layout_width="match_parent"
android:layout_height="150dp"
map:liteMode="true"
map:mapType="none"
android:layout_below="@id/lite_listrow_text" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/layout_linear"
android:title="@string/linear"
app:showAsAction="never" />
<item
android:id="@+id/layout_grid"
android:title="@string/grid"
app:showAsAction="never" />
</menu>

View File

@ -3,4 +3,5 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="white">#D0FFFFFF</color>
</resources>

View File

@ -18,4 +18,67 @@
<string name="demo_title">Google Maps API Demos</string>
<string name="no_demos">No demos</string>
<string name="play_services_not_installed">Google Play services is not installed on this device.</string>
<!-- Basic Map Demo -->
<string name="basic_demo_label">Basic Map</string>
<string name="basic_demo_details">Launches a map with marker pointing at Sydney.</string>
<!-- Circle Demo -->
<string name="circle_demo_label">Circle Demo</string>
<string name="circle_demo_details">Demonstrate how to add circles to a map</string>
<string name="properties_circle">Properties for Circle(s)</string>
<!-- Lite List Demo -->
<string name="lite_list_demo_label">Lite List Demo</string>
<string name="lite_list_demo_details">Show a list of Lite Map of different locations using RecyclerView with LinearLayoutManager and GridLayoutManager</string>
<string name="linear">Linear</string>
<string name="grid">Grid</string>
<!-- Marker Close Info Window On Retap Demo -->
<string name="close_info_window_demo_label">Close Info Window Demo</string>
<string name="close_info_window_demo_details">Demonstrates how to close the info window when the currently selected marker is retapped.</string>
<!-- Polygon Demo -->
<string name="clickable">Clickable</string>
<string name="fill_alpha">Fill Alpha</string>
<string name="fill_hue">Fill Hue</string>
<string name="joint_type_bevel">Bevel</string>
<string name="joint_type_default">Default</string>
<string name="joint_type_round">Round</string>
<string name="pattern_dashed">Dashed</string>
<string name="pattern_dotted">Dotted</string>
<string name="pattern_mixed">Mixed</string>
<string name="pattern_solid">Solid</string>
<string name="polygon_demo_description">Demonstrates how to add Polygons to a map.</string>
<string name="polygon_demo_details">Demonstrates how to add Polygons to a map</string>
<string name="polygon_demo_label">Polygons</string>
<string name="properties_australia_polygon">Properties for Polygon over Australia</string>
<string name="stroke_alpha">Stroke Alpha</string>
<string name="stroke_hue">Stroke Hue</string>
<string name="stroke_joint_type">Stroke Joint Type</string>
<string name="stroke_pattern">Stroke Pattern</string>
<string name="stroke_width">Stroke Width</string>
<!-- StreetView Panorama Navigation Demo -->
<string name="street_view_panorama_navigation_demo_label">Street View Panorama Navigation Demo</string>
<string name="street_view_panorama_navigation_demo_details">Street View Panorama with programmatic navigation</string>
<string name="request_position">Position</string>
<string name="walk_panorama">Walk</string>
<string name="go_to_invalid">Go to Invalid Point</string>
<string name="go_to_san_francisco">Go to San Francisco</string>
<string name="go_to_santorini">Go to Santorini</string>
<!-- UI Settings Demo -->
<string name="ui_settings_demo_label">UI Settings Demo</string>
<string name="ui_settings_demo_details">Demonstrate how to toggle the UI of a map</string>
<string name="location">Location permission is required to run the demo</string>
<string name="checkbox_zoom">Zoom</string>
<string name="checkbox_compass">Compass</string>
<string name="checkbox_my_location_layer">My Location</string>
<string name="checkbox_level_picker">Level Picker</string>
<string name="checkbox_map_toolbar">Map Toolbar</string>
<string name="checkbox_zoom_gesture">Zoom Gestures</string>
<string name="checkbox_scroll_gesture">Scroll Gestures</string>
<string name="checkbox_tilt_gesture">Tilt Gestures</string>
<string name="checkbox_rotate_gesture">Rotate Gestures</string>
</resources>