Skip to content

Commit f3606e9

Browse files
author
Eugene
committed
Remove TwoStepsToOneStepSearchEngineAdapter
Making multiple subsequent calls to /retrieve turned out to be undesired for billing and performance reasons, so this code change only calls /retrieve for the final selection.
1 parent 131a003 commit f3606e9

File tree

32 files changed

+644
-426
lines changed

32 files changed

+644
-426
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Breaking changes
66
- [CORE] Access token needs to be assigned via `MapboxOptions.accessToken` now
7+
- [Address Autofill, Place Autocomplete] Search is a two-steps action now, i.e. it returns `Suggestion`s (without the geo coordinate) at the first step and `Result` after suggestion selection. The `coordinate` field is no longer available in `Suggestion`.
8+
- [Address Autofill] `suggestions()` is renamed to `reverseGeocoding()`
79

810
### Mapbox dependencies
911
- Search Native SDK `2.0.0-alpha.4`

MapboxSearch/autofill/api/api-metalava.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ package com.mapbox.search.autofill {
44
public interface AddressAutofill {
55
method public default static com.mapbox.search.autofill.AddressAutofill create(com.mapbox.common.location.LocationProvider? locationProvider = <anonymous class>());
66
method public default static final com.mapbox.search.autofill.AddressAutofill create();
7+
method public suspend Object? reverseGeocoding(com.mapbox.geojson.Point point, com.mapbox.search.autofill.AddressAutofillOptions options, kotlin.coroutines.Continuation<? super com.mapbox.bindgen.Expected<java.lang.Exception,java.util.List<com.mapbox.search.autofill.AddressAutofillResult>>> p);
78
method public suspend Object? select(com.mapbox.search.autofill.AddressAutofillSuggestion suggestion, kotlin.coroutines.Continuation<? super com.mapbox.bindgen.Expected<java.lang.Exception,com.mapbox.search.autofill.AddressAutofillResult>> p);
8-
method public suspend Object? suggestions(com.mapbox.geojson.Point point, com.mapbox.search.autofill.AddressAutofillOptions options, kotlin.coroutines.Continuation<? super com.mapbox.bindgen.Expected<java.lang.Exception,java.util.List<com.mapbox.search.autofill.AddressAutofillSuggestion>>> p);
99
method public suspend Object? suggestions(com.mapbox.search.autofill.Query query, com.mapbox.search.autofill.AddressAutofillOptions options, kotlin.coroutines.Continuation<? super com.mapbox.bindgen.Expected<java.lang.Exception,java.util.List<com.mapbox.search.autofill.AddressAutofillSuggestion>>> p);
1010
field public static final com.mapbox.search.autofill.AddressAutofill.Companion Companion;
1111
}
@@ -26,16 +26,16 @@ package com.mapbox.search.autofill {
2626

2727
@kotlinx.parcelize.Parcelize public final class AddressAutofillResult implements android.os.Parcelable {
2828
method public com.mapbox.search.autofill.AddressComponents getAddress();
29+
method public com.mapbox.geojson.Point getCoordinate();
2930
method public com.mapbox.search.autofill.AddressAutofillSuggestion getSuggestion();
3031
property public final com.mapbox.search.autofill.AddressComponents address;
32+
property public final com.mapbox.geojson.Point coordinate;
3133
property public final com.mapbox.search.autofill.AddressAutofillSuggestion suggestion;
3234
}
3335

3436
@kotlinx.parcelize.Parcelize public final class AddressAutofillSuggestion implements android.os.Parcelable {
35-
method public com.mapbox.geojson.Point getCoordinate();
3637
method public String getFormattedAddress();
3738
method public String getName();
38-
property public final com.mapbox.geojson.Point coordinate;
3939
property public final String formattedAddress;
4040
property public final String name;
4141
}

MapboxSearch/autofill/api/autofill.api

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ public abstract interface class com/mapbox/search/autofill/AddressAutofill {
22
public static final field Companion Lcom/mapbox/search/autofill/AddressAutofill$Companion;
33
public static fun create ()Lcom/mapbox/search/autofill/AddressAutofill;
44
public static fun create (Lcom/mapbox/common/location/LocationProvider;)Lcom/mapbox/search/autofill/AddressAutofill;
5+
public abstract fun reverseGeocoding (Lcom/mapbox/geojson/Point;Lcom/mapbox/search/autofill/AddressAutofillOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
56
public abstract fun select (Lcom/mapbox/search/autofill/AddressAutofillSuggestion;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
6-
public abstract fun suggestions (Lcom/mapbox/geojson/Point;Lcom/mapbox/search/autofill/AddressAutofillOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
77
public abstract fun suggestions (Lcom/mapbox/search/autofill/Query;Lcom/mapbox/search/autofill/AddressAutofillOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
88
}
99

@@ -41,6 +41,7 @@ public final class com/mapbox/search/autofill/AddressAutofillResult : android/os
4141
public fun describeContents ()I
4242
public fun equals (Ljava/lang/Object;)Z
4343
public final fun getAddress ()Lcom/mapbox/search/autofill/AddressComponents;
44+
public final fun getCoordinate ()Lcom/mapbox/geojson/Point;
4445
public final fun getSuggestion ()Lcom/mapbox/search/autofill/AddressAutofillSuggestion;
4546
public fun hashCode ()I
4647
public fun toString ()Ljava/lang/String;
@@ -59,7 +60,6 @@ public final class com/mapbox/search/autofill/AddressAutofillSuggestion : androi
5960
public static final field CREATOR Landroid/os/Parcelable$Creator;
6061
public fun describeContents ()I
6162
public fun equals (Ljava/lang/Object;)Z
62-
public final fun getCoordinate ()Lcom/mapbox/geojson/Point;
6363
public final fun getFormattedAddress ()Ljava/lang/String;
6464
public final fun getName ()Ljava/lang/String;
6565
public fun hashCode ()I

MapboxSearch/autofill/src/androidTest/java/com/mapbox/search/autofill/AddressAutofillIntegrationTest.kt

+31-11
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ import com.mapbox.search.base.core.CoreApiType
1313
import com.mapbox.search.base.core.CoreEngineOptions
1414
import com.mapbox.search.base.core.CoreSearchEngine
1515
import com.mapbox.search.base.core.getUserActivityReporter
16-
import com.mapbox.search.base.engine.TwoStepsToOneStepSearchEngineAdapter
1716
import com.mapbox.search.base.location.LocationEngineAdapter
1817
import com.mapbox.search.base.location.WrapperLocationProvider
1918
import com.mapbox.search.base.location.defaultLocationProvider
2019
import com.mapbox.search.common.IsoCountryCode
2120
import com.mapbox.search.common.IsoLanguageCode
2221
import com.mapbox.search.common.SearchRequestException
22+
import kotlinx.coroutines.async
23+
import kotlinx.coroutines.awaitAll
2324
import kotlinx.coroutines.runBlocking
2425
import okhttp3.mockwebserver.Dispatcher
2526
import okhttp3.mockwebserver.MockResponse
@@ -53,7 +54,7 @@ internal class AddressAutofillIntegrationTest {
5354
)
5455

5556
addressAutofill = AddressAutofillImpl(
56-
searchEngine = engine,
57+
autofillEngine = engine,
5758
activityReporter = getUserActivityReporter()
5859
)
5960
}
@@ -96,7 +97,7 @@ internal class AddressAutofillIntegrationTest {
9697
val point = Point.fromLngLat(-77.03398187174899, 38.8999032596197)
9798

9899
runBlocking {
99-
addressAutofill.suggestions(point, options)
100+
addressAutofill.reverseGeocoding(point, options)
100101
}
101102

102103
val request = mockServer.takeRequest()
@@ -148,7 +149,6 @@ internal class AddressAutofillIntegrationTest {
148149

149150
val firstSuggestion = results.first()
150151
assertEquals("740 15th St NW", firstSuggestion.name)
151-
assertEquals(Point.fromLngLat(-77.03375, 38.89936), firstSuggestion.coordinate)
152152

153153
val selectionResponse = runBlocking {
154154
addressAutofill.select(firstSuggestion)
@@ -167,6 +167,13 @@ internal class AddressAutofillIntegrationTest {
167167
assertEquals("United States", resultAddress.country)
168168
assertEquals("us", resultAddress.countryIso1)
169169
assertEquals("US-DC", resultAddress.countryIso2)
170+
171+
val autofillResult = runBlocking {
172+
addressAutofill.select(firstSuggestion)
173+
}
174+
assertTrue(autofillResult.isValue)
175+
val autofillResultValue: AddressAutofillResult = requireNotNull(autofillResult.value)
176+
assertEquals(Point.fromLngLat(-77.03375, 38.89936), autofillResultValue.coordinate)
170177
}
171178

172179
@Test
@@ -187,7 +194,16 @@ internal class AddressAutofillIntegrationTest {
187194
assertTrue(response.isValue)
188195

189196
val results = requireNotNull(response.value)
190-
assertEquals(2, results.size)
197+
assertEquals(3, results.size)
198+
199+
val autofillResult = runBlocking {
200+
results.map { suggestion ->
201+
async {
202+
addressAutofill.select(suggestion)
203+
}
204+
}.awaitAll()
205+
}.filter { result -> result.isValue }
206+
assertEquals(2, autofillResult.size)
191207
}
192208

193209
@Test
@@ -208,10 +224,15 @@ internal class AddressAutofillIntegrationTest {
208224
val response = runBlocking {
209225
addressAutofill.suggestions(TEST_QUERY, AddressAutofillOptions())
210226
}
227+
assertTrue(response.isValue)
228+
assertEquals(3, response.value!!.size)
211229

212-
assertTrue(response.isError)
213-
val error = requireNotNull(response.error)
214-
assertEquals(SearchRequestException("", 501), error)
230+
response.value!!.map { suggestion ->
231+
val selectionResult = runBlocking {
232+
addressAutofill.select(suggestion)
233+
}
234+
assertTrue(selectionResult.isError)
235+
}
215236
}
216237

217238
@Test
@@ -282,7 +303,7 @@ internal class AddressAutofillIntegrationTest {
282303
app: Application,
283304
url: String,
284305
locationProvider: LocationProvider?
285-
): TwoStepsToOneStepSearchEngineAdapter {
306+
): AutofillSearchEngine {
286307
val coreEngine = CoreSearchEngine(
287308
CoreEngineOptions(
288309
baseUrl = url,
@@ -295,8 +316,7 @@ internal class AddressAutofillIntegrationTest {
295316
),
296317
)
297318

298-
return TwoStepsToOneStepSearchEngineAdapter(
299-
apiType = CoreApiType.AUTOFILL,
319+
return AutofillSearchEngine(
300320
coreEngine = coreEngine,
301321
requestContextProvider = SearchRequestContextProvider(app),
302322
)

MapboxSearch/autofill/src/main/java/com/mapbox/search/autofill/AddressAutofill.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ public interface AddressAutofill {
2020
* @param options Request options.
2121
* @return Result of the search request, one of error or value.
2222
*/
23-
public suspend fun suggestions(
23+
public suspend fun reverseGeocoding(
2424
point: Point,
2525
options: AddressAutofillOptions
26-
): Expected<Exception, List<AddressAutofillSuggestion>>
26+
): Expected<Exception, List<AddressAutofillResult>>
2727

2828
/**
2929
* Performs forward geocoding request.

MapboxSearch/autofill/src/main/java/com/mapbox/search/autofill/AddressAutofillImpl.kt

+45-27
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ import com.mapbox.search.base.core.CoreSearchEngine
1313
import com.mapbox.search.base.core.createCoreReverseGeoOptions
1414
import com.mapbox.search.base.core.createCoreSearchOptions
1515
import com.mapbox.search.base.core.getUserActivityReporter
16-
import com.mapbox.search.base.engine.TwoStepsToOneStepSearchEngineAdapter
1716
import com.mapbox.search.base.location.LocationEngineAdapter
1817
import com.mapbox.search.base.location.WrapperLocationProvider
1918
import com.mapbox.search.base.record.IndexableRecordResolver
2019
import com.mapbox.search.base.record.SearchHistoryService
2120
import com.mapbox.search.base.result.BaseSearchResult
21+
import com.mapbox.search.base.result.BaseSearchSuggestion
2222
import com.mapbox.search.base.result.SearchResultFactory
23+
import com.mapbox.search.base.utils.extension.flatMap
2324
import com.mapbox.search.internal.bindgen.UserActivityReporterInterface
2425
import java.util.concurrent.ExecutorService
2526
import java.util.concurrent.Executors
@@ -28,14 +29,15 @@ import java.util.concurrent.Executors
2829
* Temporary implementation of the [AddressAutofill] based on the two-step search.
2930
*/
3031
internal class AddressAutofillImpl(
31-
private val searchEngine: TwoStepsToOneStepSearchEngineAdapter,
32-
private val activityReporter: UserActivityReporterInterface
32+
private val autofillEngine: AutofillSearchEngine,
33+
private val activityReporter: UserActivityReporterInterface,
34+
private val resultFactory: AddressAutofillResultFactory = AddressAutofillResultFactory()
3335
) : AddressAutofill {
3436

35-
override suspend fun suggestions(
37+
override suspend fun reverseGeocoding(
3638
point: Point,
3739
options: AddressAutofillOptions
38-
): Expected<Exception, List<AddressAutofillSuggestion>> {
40+
): Expected<Exception, List<AddressAutofillResult>> {
3941
activityReporter.reportActivity("address-autofill-reverse-geocoding")
4042

4143
val coreOptions = createCoreReverseGeoOptions(
@@ -44,8 +46,17 @@ internal class AddressAutofillImpl(
4446
language = options.language?.let { listOf(it.code) },
4547
)
4648

47-
return searchEngine.reverseGeocoding(coreOptions).mapValue { (results, _) ->
48-
results.toAddressAutofillSuggestions()
49+
return autofillEngine.search(coreOptions).mapValue { (results, _) ->
50+
results.mapNotNull {
51+
val expected = resultFactory.createAddressAutofillResultOrNull(it)
52+
if (expected.isValue) expected.value else null
53+
}
54+
}.let { result ->
55+
if (result.isValue && result.value.isNullOrEmpty()) {
56+
ExpectedFactory.createError(Exception("No results for point $point"))
57+
} else {
58+
result
59+
}
4960
}
5061
}
5162

@@ -62,8 +73,9 @@ internal class AddressAutofillImpl(
6273
ignoreUR = true,
6374
addonAPI = mapOf("types" to "address", "streets" to "true")
6475
)
65-
return searchEngine.searchResolveImmediately(query.query, coreOptions).mapValue {
66-
it.toAddressAutofillSuggestions()
76+
77+
return autofillEngine.search(query.query, coreOptions).mapValue { (suggestions, _) ->
78+
resultFactory.createAddressAutofillSuggestions(suggestions)
6779
}
6880
}
6981

@@ -72,7 +84,28 @@ internal class AddressAutofillImpl(
7284
): Expected<Exception, AddressAutofillResult> {
7385
activityReporter.reportActivity("address-autofill-suggestion-select")
7486

75-
return ExpectedFactory.createValue(AddressAutofillResult(suggestion, suggestion.address))
87+
return if (suggestion.underlying == null) {
88+
ExpectedFactory.createError(Exception("AddressAutofillSuggestion doesn't contain underlying suggestion"))
89+
} else {
90+
val baseResult = selectRaw(suggestion.underlying).value
91+
if (baseResult == null) {
92+
ExpectedFactory.createError(Exception("No results for suggestion $suggestion"))
93+
} else {
94+
resultFactory.createAddressAutofillResultOrNull(baseResult)
95+
}
96+
}
97+
}
98+
99+
private suspend fun selectRaw(suggestion: BaseSearchSuggestion): Expected<Exception, BaseSearchResult> {
100+
return autofillEngine.select(suggestion).flatMap {
101+
when (it) {
102+
is AutofillSearchEngine.SearchSelectionResponse.Result -> ExpectedFactory.createValue(it.result)
103+
else -> {
104+
// Shouldn't happen because we don't allow suggestions of type Category and Query
105+
ExpectedFactory.createError(Exception("Unsupported suggestion type: $suggestion"))
106+
}
107+
}
108+
}
76109
}
77110

78111
internal companion object {
@@ -98,8 +131,7 @@ internal class AddressAutofillImpl(
98131
),
99132
)
100133

101-
val engine = TwoStepsToOneStepSearchEngineAdapter(
102-
apiType = CoreApiType.AUTOFILL,
134+
val engine = AutofillSearchEngine(
103135
coreEngine = coreEngine,
104136
requestContextProvider = SearchRequestContextProvider(app),
105137
historyService = SearchHistoryService.STUB,
@@ -108,23 +140,9 @@ internal class AddressAutofillImpl(
108140
)
109141

110142
return AddressAutofillImpl(
111-
searchEngine = engine,
143+
autofillEngine = engine,
112144
activityReporter = getUserActivityReporter()
113145
)
114146
}
115-
116-
private fun List<BaseSearchResult>.toAddressAutofillSuggestions() = mapNotNull { it.toAddressAutofillSuggestion() }
117-
118-
private fun BaseSearchResult.toAddressAutofillSuggestion(): AddressAutofillSuggestion? {
119-
// Filtering incomplete results
120-
val autofillAddress = AddressComponents.fromCoreSdkAddress(address, metadata) ?: return null
121-
122-
return AddressAutofillSuggestion(
123-
name = name,
124-
formattedAddress = fullAddress ?: autofillAddress.formattedAddress(),
125-
address = autofillAddress,
126-
coordinate = coordinate,
127-
)
128-
}
129147
}
130148
}

MapboxSearch/autofill/src/main/java/com/mapbox/search/autofill/AddressAutofillResult.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.mapbox.search.autofill
22

33
import android.os.Parcelable
4+
import com.mapbox.geojson.Point
45
import kotlinx.parcelize.Parcelize
56

67
/**
@@ -14,6 +15,11 @@ public class AddressAutofillResult internal constructor(
1415
*/
1516
public val suggestion: AddressAutofillSuggestion,
1617

18+
/**
19+
* Place geographic point.
20+
*/
21+
public val coordinate: Point,
22+
1723
/**
1824
* Detailed address components like street, house number, etc.
1925
*/
@@ -30,6 +36,7 @@ public class AddressAutofillResult internal constructor(
3036
other as AddressAutofillResult
3137

3238
if (suggestion != other.suggestion) return false
39+
if (coordinate != other.coordinate) return false
3340
if (address != other.address) return false
3441

3542
return true
@@ -40,6 +47,7 @@ public class AddressAutofillResult internal constructor(
4047
*/
4148
override fun hashCode(): Int {
4249
var result = suggestion.hashCode()
50+
result = 31 * result + coordinate.hashCode()
4351
result = 31 * result + address.hashCode()
4452
return result
4553
}
@@ -48,6 +56,6 @@ public class AddressAutofillResult internal constructor(
4856
* @suppress
4957
*/
5058
override fun toString(): String {
51-
return "AddressAutofillResult(suggestion=$suggestion, address=$address)"
59+
return "AddressAutofillResult(suggestion=$suggestion, coordinate=$coordinate, address=$address)"
5260
}
5361
}

0 commit comments

Comments
 (0)