diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d0af9d0..86fca08 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,17 @@ +# Copyright 2024 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 +# +# http://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. + version: 2 updates: - package-ecosystem: gradle diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index a1b107f..57a697a 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -1,3 +1,17 @@ +# Copyright 2024 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 +# +# http://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. + rebaseMergeAllowed: true squashMergeAllowed: true mergeCommitAllowed: false diff --git a/places-ktx/build.gradle b/places-ktx/build.gradle index c1faec8..8a26610 100644 --- a/places-ktx/build.gradle +++ b/places-ktx/build.gradle @@ -42,13 +42,20 @@ android { testOptions { unitTests.returnDefaultValues = true } + + buildTypes { + debug { + testCoverageEnabled = true + } + } + namespace "com.google.android.libraries.places.ktx" } dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.24' implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1') - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0" implementation "com.android.volley:volley:1.2.1" implementation 'androidx.multidex:multidex:2.0.1' api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.1" @@ -60,4 +67,5 @@ dependencies { testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" testImplementation "junit:junit:4.13.2" testImplementation "org.mockito:mockito-core:5.11.0" + testImplementation "com.google.truth:truth:1.4.2" } \ No newline at end of file diff --git a/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/model/AutocompletePrediction.kt b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/model/AutocompletePrediction.kt index cae9245..ec2098b 100644 --- a/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/model/AutocompletePrediction.kt +++ b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/model/AutocompletePrediction.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 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 + * + * http://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.google.android.libraries.places.ktx.api.model import com.google.android.libraries.places.api.model.AutocompletePrediction diff --git a/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/PlacesClient.kt b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/PlacesClient.kt index d4772b4..f24fdc2 100644 --- a/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/PlacesClient.kt +++ b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/PlacesClient.kt @@ -30,6 +30,8 @@ import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse import com.google.android.libraries.places.api.net.IsOpenResponse import com.google.android.libraries.places.api.net.PlacesClient +import com.google.android.libraries.places.api.net.SearchByTextRequest +import com.google.android.libraries.places.api.net.SearchByTextResponse import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.tasks.await @@ -135,4 +137,24 @@ public suspend fun PlacesClient.awaitIsOpen( val request = isOpenRequest(placeId, utcTimeMillis) { cancellationToken = cancellationTokenSource.token } return this.isOpen(request).await(cancellationTokenSource) -} \ No newline at end of file +} + +@ExperimentalCoroutinesApi +/** + * Wraps [PlacesClient.searchByText] in a suspending function. + * + * Fetches the place(s) of interest using a text query. If an error occurred, an [ApiException] will + * be thrown. + */ +public suspend fun PlacesClient.awaitSearchByText( + textQuery: String, + placeFields: List, + actions: SearchByTextRequest.Builder.() -> Unit = {}, +): SearchByTextResponse { + val cancellationTokenSource = CancellationTokenSource() + val request = searchByTextRequest(textQuery, placeFields) { + actions() + cancellationToken = cancellationTokenSource.token + } + return this.searchByText(request).await(cancellationTokenSource) +} diff --git a/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequest.kt b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequest.kt new file mode 100644 index 0000000..25c2e26 --- /dev/null +++ b/places-ktx/src/main/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequest.kt @@ -0,0 +1,56 @@ +// Copyright 2024 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 +// +// http://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.google.android.libraries.places.ktx.api.net + +import com.google.android.libraries.places.api.model.Place +import com.google.android.libraries.places.api.net.SearchByTextRequest + +public enum class PriceLevel(public val value: Int) { + FREE(0), // Note: not for use in the API call. + INEXPENSIVE(1), + MODERATE(2), + EXPENSIVE(3), + VERY_EXPENSIVE(4) +} + +/** + * Builds a new [SearchByTextRequest]. + * + * @param textQuery the query string to search + * @param placeFields the fields of the place to be requested + * @param actions the actions to apply to the [SearchByTextRequest.Builder] + * @return the constructed [SearchByTextRequest] + */ +public fun searchByTextRequest( + textQuery: String, + placeFields: List, + actions: SearchByTextRequest.Builder.() -> Unit = {}, +): SearchByTextRequest { + return SearchByTextRequest.builder(textQuery, placeFields) + .apply(actions) + .build() +} + +public fun SearchByTextRequest.Builder.setPriceLevels( + priceLevels: Collection +): SearchByTextRequest.Builder { + return this.setPriceLevels(priceLevels.map { it.value }) +} + +public fun SearchByTextRequest.Builder.setPriceLevels( + vararg priceLevels: PriceLevel +): SearchByTextRequest.Builder { + return this.setPriceLevels(priceLevels.map { it.value }) +} diff --git a/places-ktx/src/test/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequestTest.kt b/places-ktx/src/test/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequestTest.kt new file mode 100644 index 0000000..21b73e6 --- /dev/null +++ b/places-ktx/src/test/java/com/google/android/libraries/places/ktx/api/net/SearchByTextRequestTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2024 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 + * + * http://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.google.android.libraries.places.ktx.api.net + +import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.tasks.CancellationTokenSource +import com.google.android.libraries.places.api.model.CircularBounds +import com.google.android.libraries.places.api.model.Place +import com.google.android.libraries.places.api.net.SearchByTextRequest +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +internal class SearchByTextRequestTest { + @Test + fun testBuilderNoActions() { + val request = searchByTextRequest( + textQuery = "test query", + placeFields = listOf(Place.Field.NAME) + ) + + assertThat(request.textQuery).isEqualTo("test query") + assertThat(request.placeFields).containsExactly(Place.Field.NAME) + } + + @Test + fun testBuilderWithActions() { + val cancellationToken = CancellationTokenSource().token + val ashland = LatLng(42.193893370553916, -122.7088890892941) + val radiusInMeters = 1500.0 + + val request = searchByTextRequest( + textQuery = "test query", + placeFields = listOf(Place.Field.NAME, Place.Field.ADDRESS), + ) { + setCancellationToken(cancellationToken) + includedType = "national_park" + isOpenNow = true + minRating = 4.0 + setPriceLevels(PriceLevel.MODERATE, PriceLevel.EXPENSIVE) + rankPreference = SearchByTextRequest.RankPreference.RELEVANCE + regionCode = "US" + + locationBias = CircularBounds.newInstance(ashland, radiusInMeters) + } + + assertThat(request.locationBias) + .isEqualTo(CircularBounds.newInstance(ashland, radiusInMeters)) + assertThat(request.isOpenNow).isTrue() + assertThat(request.minRating).isEqualTo(4.0) + assertThat(request.priceLevels) + .containsExactly(PriceLevel.MODERATE.value, PriceLevel.EXPENSIVE.value) + assertThat(request.rankPreference).isEqualTo(SearchByTextRequest.RankPreference.RELEVANCE) + assertThat(request.regionCode).isEqualTo("US") + assertThat(request.includedType).isEqualTo("national_park") + assertThat(request.textQuery).isEqualTo("test query") + } +} \ No newline at end of file diff --git a/places-ktx/src/test/java/com/google/android/libraries/places/ktx/model/AutocompletePredictionTest.kt b/places-ktx/src/test/java/com/google/android/libraries/places/ktx/model/AutocompletePredictionTest.kt index 12f004e..d7f7db4 100644 --- a/places-ktx/src/test/java/com/google/android/libraries/places/ktx/model/AutocompletePredictionTest.kt +++ b/places-ktx/src/test/java/com/google/android/libraries/places/ktx/model/AutocompletePredictionTest.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 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 + * + * http://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.google.android.libraries.places.ktx.model import com.google.android.libraries.places.api.model.Place