Skip to content

Commit

Permalink
Merge pull request #17 from XYOracleNetwork/feature/location-activity
Browse files Browse the repository at this point in the history
Feature/location activity
  • Loading branch information
jonesmac authored Nov 8, 2024
2 parents 7df3b12 + 1d401de commit 778270f
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 84 deletions.
26 changes: 16 additions & 10 deletions sdk/src/androidTest/java/network/xyo/client/LocationWitnessTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package network.xyo.client
import android.Manifest
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.rule.GrantPermissionRule
import network.xyo.client.witness.location.info.LocationActivity
import network.xyo.client.witness.location.info.XyoLocationPayload
import network.xyo.client.witness.location.info.XyoLocationWitness
import org.junit.Rule
Expand All @@ -16,17 +18,21 @@ class LocationWitnessTest {
Manifest.permission.ACCESS_FINE_LOCATION
)

@get:Rule
val activityRule = ActivityScenarioRule(LocationActivity::class.java)

@Test
fun testObserve() {
assert(true == true)
// bring back once we can successfully start listening for locations changes or mocking them
// Get the application context
// val context = ApplicationProvider.getApplicationContext<Context>()
//
// val witness = XyoLocationWitness()
// val payload = witness.observe(context)
//
// assertInstanceOf<XyoLocationPayload>(payload)
// assert(payload.schema == "network.xyo.location.android")
// Get the application context
val context = ApplicationProvider.getApplicationContext<Context>()

val witness = XyoLocationWitness()
val payload = witness.observe(context)

assertInstanceOf<XyoLocationPayload>(payload)
assert(payload.schema == "network.xyo.location.android")
assert((payload.currentLocation) !== null)
assert(payload.currentLocation?.coords?.latitude !== null)
assert(payload.currentLocation?.coords?.longitude !== null)
}
}
4 changes: 4 additions & 0 deletions sdk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<application>
<activity android:name="network.xyo.client.witness.location.info.LocationActivity" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package network.xyo.client.witness.location.info

import android.annotation.SuppressLint
import android.app.Activity
import android.os.Bundle
import android.os.Looper
import android.util.Log
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices

const val REQUESTING_LOCATION_UPDATES_KEY = "REQUESTING_LOCATION_UPDATES_KEY"

class LocationActivity : Activity() {
private var requestingLocationUpdates: Boolean = false
private lateinit var locationCallback: LocationCallback

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

requestingLocationUpdates = true
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
// No action necessary but we need to start the activity to get location results
Log.i("xyoClient", "LocationActivity: locationCallback fired successfully")
}
}
startLocationUpdates()
}

override fun onResume() {
super.onResume()
if (requestingLocationUpdates) startLocationUpdates()
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates)
super.onSaveInstanceState(outState)
}

// Already checking in class
@SuppressLint("MissingPermission")
private fun startLocationUpdates() {
if (LocationPermissions.check((this))) {
val locationRequest: LocationRequest = LocationRequest.Builder(5000).build()
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper())
return
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package network.xyo.client.witness.location.info

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.util.Log
import androidx.core.app.ActivityCompat
import com.google.android.gms.common.GoogleApiAvailability

class LocationPermissions {
companion object {
fun check(context: Context): Boolean {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e("xyoClient", "ACCESS_FINE_LOCATION permission not allowed")
return false
}

if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e("xyoClient", "ACCESS_FINE_LOCATION permission not allowed")
return false
}
return true
}

fun checkGooglePlayServices(context: Context): Boolean {
val gpInstance = GoogleApiAvailability.getInstance()
val available = gpInstance.isGooglePlayServicesAvailable(context)
val googlePlayServicesAvailable = available == 1
if (googlePlayServicesAvailable) {
Log.e("xyoClient", "Google Play Service not installed")
return false
}
return true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package network.xyo.client.witness.location.info

import android.annotation.SuppressLint
import android.content.Context
import android.location.Location
import android.util.Log
import com.google.android.gms.location.LocationServices
import com.squareup.moshi.JsonClass
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

@JsonClass(generateAdapter = true)
class XyoLocationCurrent {
companion object {

@SuppressLint("MissingPermission")
fun detect(context: Context): CurrentLocation? {
if (LocationPermissions.check((context)) && LocationPermissions.checkGooglePlayServices(context)) {
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
var coordinates: Coordinates? = null

try {
val latch = CountDownLatch(1)

fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
if (location != null) {
Log.w("xyoClient", "Location was found")
coordinates = setCoordinatesFromLocation(location)
// countDown to zero to lift the latch
latch.countDown()
} else {
// countDown to zero to lift the latch
latch.countDown()
Log.e("xyoClient","Location not available")
}
}
.addOnFailureListener {
Log.e("xyoClient","Failed to get location: ${it.message}")
}
// Wait for up to 5 seconds for the location
latch.await(5, TimeUnit.SECONDS)

if (coordinates == null) {
return null
} else {
return CurrentLocation(coordinates!!, System.currentTimeMillis())
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
return null
}

private fun setCoordinatesFromLocation(location: Location): Coordinates {
return Coordinates(
location.accuracy,
location.altitude,
null,
location.bearing,
location.latitude,
location.longitude,
location.speed
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
package network.xyo.client.witness.location.info

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.util.Log
import androidx.core.content.ContextCompat
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.location.LocationServices
import com.squareup.moshi.JsonClass
import network.xyo.client.payload.XyoPayload
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

data class Coordinates(
val accuracy: Float?,
Expand All @@ -32,77 +24,17 @@ data class CurrentLocation(

@JsonClass(generateAdapter = true)
class XyoLocationPayload (
currentLocation: CurrentLocation?
val currentLocation: CurrentLocation? = null
): XyoPayload() {
override var schema: String = "network.xyo.location.android"

companion object {

@SuppressLint("MissingPermission")
fun detect(context: Context): XyoLocationPayload? {
val gpInstance = GoogleApiAvailability.getInstance()
val available = gpInstance.isGooglePlayServicesAvailable(context)
val googlePlayServicesAvailable = available == 1
if (googlePlayServicesAvailable) {
Log.e("xyoClient", "Google Play Service not installed")
return null
}

if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e("xyoClient", "ACCESS_FINE_LOCATION permission not allowed")
return null
}

if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.e("xyoClient", "ACCESS_FINE_LOCATION permission not allowed")
return null
}

val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
var coordinates: Coordinates? = null

try {
val latch = CountDownLatch(1)

fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
if (location != null) {
Log.w("xyoClient", "Location was null")
coordinates = Coordinates(
location.accuracy,
location.altitude,
null,
location.bearing,
location.latitude,
location.longitude,
location.speed
)
// countDown to zero to lift the latch
latch.countDown()
} else {
// countDown to zero to lift the latch
latch.countDown()
Log.e("xyoClient","Location not available")
}
}
.addOnFailureListener {
Log.e("xyoClient","Failed to get location: ${it.message}")
}
// Wait for up to 5 seconds for the location
latch.await(5, TimeUnit.SECONDS)

if (coordinates == null) {
return null
} else {
val currentLocation = CurrentLocation(coordinates!!, System.currentTimeMillis())
return XyoLocationPayload(currentLocation)
}
} catch (e: InterruptedException) {
e.printStackTrace()
}
return null

return XyoLocationPayload(
XyoLocationCurrent.detect(context)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class XyoSystemInfoPayload(
val os: XyoSystemInfoOs? = null,
): XyoPayload () {
override var schema: String = "network.xyo.system.info.android"

companion object {

@RequiresApi(Build.VERSION_CODES.M)
Expand Down

0 comments on commit 778270f

Please sign in to comment.