Skip to content

Commit 83f961d

Browse files
authored
feat: added StreetViewUtil (#1200)
* feat: added StreetViewUtil * docs: added documentation for StreetViewUtil
1 parent e9936ea commit 83f961d

File tree

12 files changed

+200
-20
lines changed

12 files changed

+200
-20
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ range of applications using the [Google Maps SDK for Android][android-site].
2121
computeArea
2222
- **KML** — displays KML data
2323
- **GeoJSON** — displays and styles GeoJSON data
24+
- **StreetView Utility** — checks if a given StreetView location exists
2425

2526
<p align="center"><img width="90%" vspace="20" src="https://cloud.githubusercontent.com/assets/1950036/6629704/f57bc6d8-c908-11e4-815a-0d909fe02f99.gif"></p>
2627

@@ -289,6 +290,20 @@ _Old_
289290

290291
</details>
291292

293+
## Usage guide
294+
295+
The full documentation can be found here [Google Maps Platform documentation][devsite-guide].
296+
297+
For a quick snippet on the StreetViewUtil class, keep reading.
298+
299+
The StreetViewUtil class provides functionality to check whether a location is supported in StreetView. To call it, use the following snippet:
300+
301+
```kotlin
302+
StreetViewUtils.fetchStreetViewData(LatLng(8.1425918, 11.5386121), BuildConfig.MAPS_API_KEY)
303+
```
304+
305+
`fetchStreetViewData` will return `NOT_FOUND`, `OK` or `ZERO_RESULTS`, depending on the response.
306+
292307
## Support
293308

294309
Encounter an issue while using this library?

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ buildscript {
2727
classpath 'com.android.tools.build:gradle:7.3.1'
2828
classpath 'com.hiya:jacoco-android:0.2'
2929
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
30-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
30+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
3131
}
3232
}
3333

demo/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@ dependencies {
5454
implementation 'androidx.appcompat:appcompat:1.7.0-alpha01'
5555
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
5656

57-
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
57+
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"
5858
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
59+
60+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.0'
61+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0'
62+
5963
// [END_EXCLUDE]
6064
}
6165
// [END maps_android_utils_install_snippet]

demo/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<activity android:name=".KmlDemoActivity" />
6969
<activity android:name=".MultiLayerDemoActivity" />
7070
<activity android:name=".AnimationUtilDemoActivity" />
71+
<activity android:name=".StreetViewDemoActivity" />
7172

7273
</application>
7374

demo/src/main/java/com/google/maps/android/utils/demo/MainActivity.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013 Google Inc.
2+
* Copyright 2023 Google Inc.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ protected void onCreate(Bundle savedInstanceState) {
5757
addDemo("KML Layer Overlay", KmlDemoActivity.class);
5858
addDemo("Multi Layer", MultiLayerDemoActivity.class);
5959
addDemo("AnimationUtil sample", AnimationUtilDemoActivity.class);
60+
addDemo("Street View Demo", StreetViewDemoActivity.class);
6061
}
6162

6263
private void addDemo(String demoName, Class<? extends Activity> activityClass) {

demo/src/main/java/com/google/maps/android/utils/demo/SampleManager.java

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.google.maps.android.utils.demo
2+
3+
import android.app.Activity
4+
import android.os.Bundle
5+
import android.widget.TextView
6+
import com.google.android.gms.maps.model.LatLng
7+
import com.google.maps.android.StreetViewUtils
8+
import kotlinx.coroutines.DelicateCoroutinesApi
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.GlobalScope
11+
import kotlinx.coroutines.launch
12+
13+
class StreetViewDemoActivity : Activity() {
14+
15+
@OptIn(DelicateCoroutinesApi::class)
16+
override fun onCreate(savedInstanceState: Bundle?) {
17+
super.onCreate(savedInstanceState)
18+
setContentView(R.layout.street_view_demo)
19+
20+
GlobalScope.launch(Dispatchers.Main) {
21+
val response1 =
22+
StreetViewUtils.fetchStreetViewData(LatLng(48.1425918, 11.5386121), BuildConfig.MAPS_API_KEY)
23+
val response2 = StreetViewUtils.fetchStreetViewData(LatLng(8.1425918, 11.5386121), BuildConfig.MAPS_API_KEY)
24+
25+
findViewById<TextView>(R.id.textViewFirstLocation).text = "Location 1 is supported in StreetView: $response1"
26+
findViewById<TextView>(R.id.textViewSecondLocation).text = "Location 2 is supported in StreetView: $response2"
27+
}
28+
}
29+
}
30+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
7+
<TextView
8+
android:id="@+id/textViewFirstLocation"
9+
android:layout_width="wrap_content"
10+
android:layout_height="wrap_content" />
11+
<TextView
12+
android:id="@+id/textViewSecondLocation"
13+
android:layout_width="wrap_content"
14+
android:layout_height="wrap_content" />
15+
</LinearLayout>

library/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
plugins {
1717
id 'kotlin-android'
18+
id 'org.jetbrains.kotlin.android'
1819
}
1920

2021
android {
@@ -56,11 +57,14 @@ android {
5657

5758
dependencies {
5859
implementation 'com.google.android.gms:play-services-maps:18.1.0'
60+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.0'
5961
implementation 'androidx.appcompat:appcompat:1.6.1'
62+
implementation 'androidx.core:core-ktx:1.10.1'
6063
lintPublish project(':lint-checks')
6164
testImplementation 'junit:junit:4.13.2'
62-
testImplementation 'org.robolectric:robolectric:4.7.3'
65+
testImplementation 'org.robolectric:robolectric:4.10.3'
6366
testImplementation 'net.sf.kxml:kxml2:2.3.0'
67+
testImplementation "io.mockk:mockk:1.13.4"
6468
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
6569
}
6670

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2023 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.maps.android
17+
18+
import kotlinx.coroutines.withContext
19+
import java.io.IOException
20+
import java.net.HttpURLConnection
21+
import java.net.URL
22+
import com.google.android.gms.maps.model.LatLng
23+
import kotlinx.coroutines.Dispatchers
24+
import org.json.JSONObject
25+
import java.io.BufferedReader
26+
import java.io.InputStreamReader
27+
28+
29+
/**
30+
* Utility functions for StreetView
31+
*/
32+
class StreetViewUtils {
33+
companion object {
34+
35+
/**
36+
* This function will check whether a location is available on StreetView or not.
37+
*
38+
* @param latLng Location to check
39+
* @param apiKey Maps API Key
40+
* @return A boolean value specifying if the location is available on Street View or not.
41+
*/
42+
suspend fun fetchStreetViewData(latLng: LatLng, apiKey: String): Status {
43+
val urlString =
44+
"https://maps.googleapis.com/maps/api/streetview/metadata?location=${latLng.latitude},${latLng.longitude}&key=$apiKey"
45+
46+
return withContext(Dispatchers.IO) {
47+
try {
48+
val url = URL(urlString)
49+
val connection = url.openConnection() as HttpURLConnection
50+
connection.requestMethod = "GET"
51+
52+
val responseCode = connection.responseCode
53+
if (responseCode == HttpURLConnection.HTTP_OK) {
54+
val inputStream = connection.inputStream
55+
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
56+
val responseString = bufferedReader.use { it.readText() }
57+
bufferedReader.close()
58+
inputStream.close()
59+
deserializeResponse(responseString).status
60+
} else {
61+
throw IOException("HTTP Error: $responseCode")
62+
}
63+
} catch (e: IOException) {
64+
e.printStackTrace()
65+
throw IOException("Network error: ${e.message}")
66+
}
67+
}
68+
}
69+
70+
private fun deserializeResponse(responseString: String): ResponseStreetView {
71+
val jsonObject = JSONObject(responseString)
72+
val statusString = jsonObject.optString("status")
73+
val status = Status.valueOf(statusString)
74+
75+
return ResponseStreetView(status)
76+
}
77+
}
78+
}
79+
80+
data class ResponseStreetView(val status: Status)
81+
82+
enum class Status {
83+
OK,
84+
ZERO_RESULTS,
85+
NOT_FOUND
86+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.google.maps.android
2+
3+
import com.google.android.gms.maps.model.LatLng
4+
import io.mockk.coEvery
5+
import io.mockk.mockkObject
6+
import kotlinx.coroutines.runBlocking
7+
import org.junit.Assert.assertEquals
8+
import org.junit.Before
9+
import org.junit.Test
10+
11+
class StreetViewUtilsTest {
12+
13+
lateinit var latLng : LatLng
14+
15+
val apiKey = "AN_API_KEY"
16+
17+
@Before
18+
fun setUp() {
19+
latLng = LatLng(37.7749, -122.4194) // San Francisco coordinates
20+
21+
// Mock the network behavior using MockK
22+
mockkObject(StreetViewUtils)
23+
coEvery { StreetViewUtils.fetchStreetViewData(any(), any()) } returns Status.NOT_FOUND
24+
coEvery { StreetViewUtils.fetchStreetViewData(latLng, apiKey) } returns Status.OK
25+
}
26+
27+
@Test
28+
fun testLocationFoundOnStreetView() = runBlocking {
29+
val status = StreetViewUtils.fetchStreetViewData(latLng, apiKey)
30+
assertEquals(Status.OK, status)
31+
}
32+
33+
@Test
34+
fun testLocationNotFoundOnStreetView() = runBlocking {
35+
val status = StreetViewUtils.fetchStreetViewData(LatLng(10.0, 20.0), apiKey)
36+
assertEquals(Status.NOT_FOUND, status)
37+
}
38+
}
39+

local.defaults.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
MAPS_API_KEY="YOUR_API_KEY"
1+
MAPS_API_KEY="AIzaSyA4SCF8hbjd5M3pq-FncAtSu1uTe_yaQBg"

0 commit comments

Comments
 (0)