Skip to content

Commit e5bcef7

Browse files
committed
replace ShadowFusedLocationProviderApi
Replaced ShadowFusedLocationProviderApi with FusedLocationApiWrapperMock as it depended on Field::class.java.getDeclaredField("modifiers") which was a reflection feature dropped in somewhere between Java 11 -> 17. Since there wasn't a straightforward way to keep this as a shadow it was worth the time instead to use dependency inject.
1 parent 49ad095 commit e5bcef7

File tree

7 files changed

+123
-215
lines changed

7 files changed

+123
-215
lines changed

OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/LocationModule.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import com.onesignal.location.internal.capture.ILocationCapturer
1212
import com.onesignal.location.internal.capture.impl.LocationCapturer
1313
import com.onesignal.location.internal.common.LocationUtils
1414
import com.onesignal.location.internal.controller.ILocationController
15+
import com.onesignal.location.internal.controller.impl.FusedLocationApiWrapperImpl
1516
import com.onesignal.location.internal.controller.impl.GmsLocationController
1617
import com.onesignal.location.internal.controller.impl.HmsLocationController
18+
import com.onesignal.location.internal.controller.impl.IFusedLocationApiWrapper
1719
import com.onesignal.location.internal.controller.impl.NullLocationController
1820
import com.onesignal.location.internal.permissions.LocationPermissionController
1921
import com.onesignal.location.internal.preferences.ILocationPreferencesService
@@ -25,11 +27,15 @@ internal class LocationModule : IModule {
2527
.provides<LocationPermissionController>()
2628
.provides<IStartableService>()
2729

30+
builder.register<FusedLocationApiWrapperImpl>().provides<IFusedLocationApiWrapper>()
2831
builder.register {
2932
val deviceService = it.getService(IDeviceService::class.java)
3033
val service =
3134
if (deviceService.isAndroidDeviceType && LocationUtils.hasGMSLocationLibrary()) {
32-
GmsLocationController(it.getService(IApplicationService::class.java))
35+
GmsLocationController(
36+
it.getService(IApplicationService::class.java),
37+
it.getService(IFusedLocationApiWrapper::class.java),
38+
)
3339
} else if (deviceService.isHuaweiDeviceType && LocationUtils.hasHMSLocationLibrary()) {
3440
HmsLocationController(it.getService(IApplicationService::class.java))
3541
} else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.onesignal.location.internal.controller.impl
2+
3+
import android.location.Location
4+
import android.os.Looper
5+
import com.google.android.gms.common.api.GoogleApiClient
6+
import com.google.android.gms.location.LocationListener
7+
import com.google.android.gms.location.LocationRequest
8+
import com.google.android.gms.location.LocationServices
9+
import com.onesignal.debug.internal.logging.Logging
10+
11+
internal class FusedLocationApiWrapperImpl : IFusedLocationApiWrapper {
12+
override fun cancelLocationUpdates(
13+
googleApiClient: GoogleApiClient,
14+
locationListener: LocationListener,
15+
) {
16+
if (googleApiClient.isConnected) {
17+
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener)
18+
} else {
19+
Logging.warn("GoogleApiClient is not connected. Unable to cancel location updates.")
20+
}
21+
}
22+
23+
override fun requestLocationUpdates(
24+
googleApiClient: GoogleApiClient,
25+
locationRequest: LocationRequest,
26+
locationListener: LocationListener,
27+
) {
28+
try {
29+
if (Looper.myLooper() == null) {
30+
Looper.prepare()
31+
}
32+
if (googleApiClient.isConnected) {
33+
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationListener)
34+
}
35+
} catch (t: Throwable) {
36+
Logging.warn("FusedLocationApi.requestLocationUpdates failed!", t)
37+
}
38+
}
39+
40+
override fun getLastLocation(googleApiClient: GoogleApiClient): Location? {
41+
if (googleApiClient.isConnected) {
42+
return LocationServices.FusedLocationApi.getLastLocation(googleApiClient)
43+
}
44+
return null
45+
}
46+
}

OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import android.location.Location
44
import android.os.Bundle
55
import android.os.Handler
66
import android.os.HandlerThread
7-
import android.os.Looper
87
import com.google.android.gms.common.ConnectionResult
98
import com.google.android.gms.common.api.GoogleApiClient
109
import com.google.android.gms.location.LocationListener
@@ -29,6 +28,7 @@ import java.io.Closeable
2928

3029
internal class GmsLocationController(
3130
private val _applicationService: IApplicationService,
31+
private val _fusedLocationApiWrapper: IFusedLocationApiWrapper,
3232
) : ILocationController {
3333
private val locationHandlerThread = LocationHandlerThread()
3434
private val startStopMutex = Mutex()
@@ -75,14 +75,14 @@ internal class GmsLocationController(
7575

7676
if (result?.isSuccess == true) {
7777
if (lastLocation == null) {
78-
var lastLocation = FusedLocationApiWrapper.getLastLocation(googleApiClient)
78+
var lastLocation = _fusedLocationApiWrapper.getLastLocation(googleApiClient)
7979
if (lastLocation != null) {
8080
setLocationAndFire(lastLocation)
8181
}
8282
}
8383

8484
// only after the connect do we save
85-
self.locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance)
85+
self.locationUpdateListener = LocationUpdateListener(_applicationService, self, proxyGoogleApiClient.realInstance, _fusedLocationApiWrapper)
8686
self.googleApiClient = proxyGoogleApiClient
8787
wasSuccessful = true
8888
} else {
@@ -121,7 +121,7 @@ internal class GmsLocationController(
121121

122122
override fun getLastLocation(): Location? {
123123
val apiInstance = googleApiClient?.realInstance ?: return null
124-
return FusedLocationApiWrapper.getLastLocation(apiInstance)
124+
return _fusedLocationApiWrapper.getLastLocation(apiInstance)
125125
}
126126

127127
override fun subscribe(handler: ILocationUpdatedHandler) = event.subscribe(handler)
@@ -162,6 +162,7 @@ internal class GmsLocationController(
162162
private val _applicationService: IApplicationService,
163163
private val _parent: GmsLocationController,
164164
private val googleApiClient: GoogleApiClient,
165+
private val _fusedLocationApiWrapper: IFusedLocationApiWrapper,
165166
) : LocationListener, IApplicationLifecycleHandler, Closeable {
166167
private var hasExistingRequest = false
167168

@@ -188,7 +189,7 @@ internal class GmsLocationController(
188189
_applicationService.removeApplicationLifecycleHandler(this)
189190

190191
if (hasExistingRequest) {
191-
FusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this)
192+
_fusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this)
192193
}
193194
}
194195

@@ -199,7 +200,7 @@ internal class GmsLocationController(
199200
}
200201

201202
if (hasExistingRequest) {
202-
FusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this)
203+
_fusedLocationApiWrapper.cancelLocationUpdates(googleApiClient, this)
203204
}
204205

205206
val updateInterval =
@@ -216,7 +217,7 @@ internal class GmsLocationController(
216217
.setMaxWaitTime((updateInterval * 1.5).toLong())
217218
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
218219
Logging.debug("GMSLocationController GoogleApiClient requestLocationUpdates!")
219-
FusedLocationApiWrapper.requestLocationUpdates(googleApiClient, locationRequest, this)
220+
_fusedLocationApiWrapper.requestLocationUpdates(googleApiClient, locationRequest, this)
220221
hasExistingRequest = true
221222
}
222223

@@ -226,43 +227,6 @@ internal class GmsLocationController(
226227
}
227228
}
228229

229-
internal object FusedLocationApiWrapper {
230-
fun cancelLocationUpdates(
231-
googleApiClient: GoogleApiClient,
232-
locationListener: LocationListener,
233-
) {
234-
if (googleApiClient.isConnected) {
235-
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, locationListener)
236-
} else {
237-
Logging.warn("GoogleApiClient is not connected. Unable to cancel location updates.")
238-
}
239-
}
240-
241-
fun requestLocationUpdates(
242-
googleApiClient: GoogleApiClient,
243-
locationRequest: LocationRequest,
244-
locationListener: LocationListener,
245-
) {
246-
try {
247-
if (Looper.myLooper() == null) {
248-
Looper.prepare()
249-
}
250-
if (googleApiClient.isConnected) {
251-
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, locationListener)
252-
}
253-
} catch (t: Throwable) {
254-
Logging.warn("FusedLocationApi.requestLocationUpdates failed!", t)
255-
}
256-
}
257-
258-
fun getLastLocation(googleApiClient: GoogleApiClient): Location? {
259-
if (googleApiClient.isConnected) {
260-
return LocationServices.FusedLocationApi.getLastLocation(googleApiClient)
261-
}
262-
return null
263-
}
264-
}
265-
266230
protected class LocationHandlerThread internal constructor() :
267231
HandlerThread("OSH_LocationHandlerThread") {
268232
var mHandler: Handler
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.onesignal.location.internal.controller.impl
2+
3+
import android.location.Location
4+
import com.google.android.gms.common.api.GoogleApiClient
5+
import com.google.android.gms.location.LocationListener
6+
import com.google.android.gms.location.LocationRequest
7+
8+
internal interface IFusedLocationApiWrapper {
9+
fun cancelLocationUpdates(
10+
googleApiClient: GoogleApiClient,
11+
locationListener: LocationListener,
12+
)
13+
14+
fun requestLocationUpdates(
15+
googleApiClient: GoogleApiClient,
16+
locationRequest: LocationRequest,
17+
locationListener: LocationListener,
18+
)
19+
20+
fun getLastLocation(googleApiClient: GoogleApiClient): Location?
21+
}

OneSignalSDK/onesignal/location/src/test/java/com/onesignal/location/internal/controller/GmsLocationControllerTests.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import android.location.Location
44
import com.onesignal.debug.LogLevel
55
import com.onesignal.debug.internal.logging.Logging
66
import com.onesignal.location.internal.controller.impl.GmsLocationController
7-
import com.onesignal.location.shadows.ShadowFusedLocationProviderApi
7+
import com.onesignal.location.mocks.FusedLocationApiWrapperMock
88
import com.onesignal.location.shadows.ShadowGoogleApiClient
99
import com.onesignal.location.shadows.ShadowGoogleApiClientBuilder
1010
import com.onesignal.mocks.AndroidMockHelper
@@ -37,11 +37,11 @@ class GmsLocationControllerTests : FunSpec({
3737
val location = Location("TEST_PROVIDER")
3838
location.latitude = 123.45
3939
location.longitude = 678.91
40+
val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location))
4041

41-
ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location))
4242
val applicationService = AndroidMockHelper.applicationService()
4343
every { applicationService.isInForeground } returns true
44-
val gmsLocationController = GmsLocationController(applicationService)
44+
val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock)
4545

4646
val spyLocationUpdateHandler = spyk<ILocationUpdatedHandler>()
4747
gmsLocationController.subscribe(spyLocationUpdateHandler)
@@ -71,11 +71,11 @@ class GmsLocationControllerTests : FunSpec({
7171
val location2 = Location("TEST_PROVIDER")
7272
location2.latitude = 678.91
7373
location2.longitude = 123.45
74+
val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2))
7475

75-
ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2))
7676
val applicationService = AndroidMockHelper.applicationService()
7777
every { applicationService.isInForeground } returns true
78-
val gmsLocationController = GmsLocationController(applicationService)
78+
val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock)
7979

8080
val spyLocationUpdateHandler = spyk<ILocationUpdatedHandler>()
8181
gmsLocationController.subscribe(spyLocationUpdateHandler)
@@ -114,10 +114,10 @@ class GmsLocationControllerTests : FunSpec({
114114
location2.latitude = 678.91
115115
location2.longitude = 123.45
116116

117-
ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2))
117+
val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2))
118118
val applicationService = AndroidMockHelper.applicationService()
119119
every { applicationService.isInForeground } returns true
120-
val gmsLocationController = GmsLocationController(applicationService)
120+
val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock)
121121

122122
val spyLocationUpdateHandler = spyk<ILocationUpdatedHandler>()
123123
gmsLocationController.subscribe(spyLocationUpdateHandler)
@@ -152,10 +152,10 @@ class GmsLocationControllerTests : FunSpec({
152152
location2.latitude = 678.91
153153
location2.longitude = 123.45
154154

155-
ShadowFusedLocationProviderApi.injectToLocationServices(listOf(location1, location2))
155+
val fusedLocationApiWrapperMock = FusedLocationApiWrapperMock(listOf(location1, location2))
156156
val applicationService = AndroidMockHelper.applicationService()
157157
every { applicationService.isInForeground } returns true
158-
val gmsLocationController = GmsLocationController(applicationService)
158+
val gmsLocationController = GmsLocationController(applicationService, fusedLocationApiWrapperMock)
159159

160160
val spyLocationUpdateHandler = spyk<ILocationUpdatedHandler>()
161161
gmsLocationController.subscribe(spyLocationUpdateHandler)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.onesignal.location.mocks
2+
3+
import android.location.Location
4+
import com.google.android.gms.common.api.GoogleApiClient
5+
import com.google.android.gms.location.LocationListener
6+
import com.google.android.gms.location.LocationRequest
7+
import com.onesignal.location.internal.controller.impl.IFusedLocationApiWrapper
8+
import java.util.LinkedList
9+
import java.util.Queue
10+
11+
internal class FusedLocationApiWrapperMock(locationsList: List<Location>) : IFusedLocationApiWrapper {
12+
private val locations: Queue<Location>
13+
14+
init {
15+
this.locations = LinkedList(locationsList)
16+
}
17+
18+
override fun cancelLocationUpdates(
19+
googleApiClient: GoogleApiClient,
20+
locationListener: LocationListener,
21+
) {}
22+
23+
override fun requestLocationUpdates(
24+
googleApiClient: GoogleApiClient,
25+
locationRequest: LocationRequest,
26+
locationListener: LocationListener,
27+
) {}
28+
29+
override fun getLastLocation(googleApiClient: GoogleApiClient): Location? {
30+
return locations.remove()
31+
}
32+
}

0 commit comments

Comments
 (0)