Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,54 +1,111 @@
package com.erooja.ghostrun_android

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.erooja.ghostrun_android.permission.LocationPermissionRequester
import com.erooja.ghostrun_android.permission.LocationPermissionUtil
import com.erooja.ghostrun_android.state.CurrentLocationState
import com.erooja.ghostrun_android.state.LocationPermissionState
import com.erooja.ghostrun_android.ui.theme.GhostRun_AndroidTheme
import com.erooja.ghostrun_android.util.GhostrunLocationManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject
lateinit var permissionRequester: LocationPermissionRequester

@Inject
lateinit var locationManager: GhostrunLocationManager

private var uiState: MainUiState by mutableStateOf(MainUiState.Loading)

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

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
permissionRequester
.permissionFlow
.collect { permissionState ->
Log.e("permissonState", permissionState.toString())
when (permissionState) {
is LocationPermissionState.ObtainLocationPermission -> {
locationManager.init()
}
is LocationPermissionState.Error -> Unit
}
}
}
}

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
locationManager
.trackingLocationFlow
.collect { locationState ->
Log.e("locationState", locationState.toString())
when (locationState) {
is CurrentLocationState.Success -> {
if (LocationPermissionUtil.isPermissionGranted(this@MainActivity)) {
uiState = MainUiState.Success(locationState.coordinate)
}
}
else -> Unit
}
}
}
}

setContent {
permissionRequester.requestPermission()

GhostRun_AndroidTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
CoordinateText(uiState)
}
}
}
}
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
fun CoordinateText(uiState: MainUiState) {

if (uiState is MainUiState.Success)
Column {
Text(
text = "longitude is ${uiState.coordinate.x}!",
)
Text(
text = "latitude is ${uiState.coordinate.y}!",
)
}
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
GhostRun_AndroidTheme {
Greeting("Android")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.erooja.ghostrun_android

import com.erooja.ghostrun_android.state.Coordinate
sealed class MainUiState {
object Loading : MainUiState()
data class Success(val coordinate: Coordinate) : MainUiState()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.erooja.ghostrun_android.permission

import android.Manifest
import android.content.Context
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
Expand Down Expand Up @@ -48,12 +49,15 @@ class LocationPermissionRequester @Inject constructor(
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
Log.e("ObtainLocationPermission", "ACCESS_FINE_LOCATION")
emitFlow(LocationPermissionState.ObtainLocationPermission)
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
Log.e("PermissionFail", "ACCESS_COARSE_LOCATION")
emitFlow(LocationPermissionState.Error.PermissionFail)
}
else -> {
Log.e("PermissionFail", "else")
emitFlow(LocationPermissionState.Error.PermissionFail)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import com.erooja.ghostrun_android.state.CurrentLocationState
import kotlinx.coroutines.flow.MutableStateFlow

object LocationPermissionUtil {
val trackingLocationFlow: MutableStateFlow<CurrentLocationState> = MutableStateFlow(
CurrentLocationState.UnInitialized)

val permissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package com.erooja.ghostrun_android.state
sealed class CurrentLocationState {
object UnInitialized: CurrentLocationState()

object Prepared: CurrentLocationState()

data class Success(
val boundBottomLeftCoordinate: Coordinate = Coordinate.Default,
val boundTopRightCoordinate: Coordinate = Coordinate.Default,
val centerCoordinate: Coordinate = Coordinate.Default,
val coordinate: Coordinate = Coordinate.Default
) : CurrentLocationState()

object Error : CurrentLocationState()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.erooja.ghostrun_android.util

import android.annotation.SuppressLint
import android.content.Context
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.erooja.ghostrun_android.permission.LocationPermissionUtil
import com.erooja.ghostrun_android.state.Coordinate
import com.erooja.ghostrun_android.state.CurrentLocationState
import dagger.hilt.android.qualifiers.ActivityContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject

@SuppressLint("MissingPermission")
class GhostrunLocationManager @Inject constructor(
@ActivityContext private val context: Context,
) {
private val lifecycleScope: CoroutineScope
get() = (context as ComponentActivity).lifecycleScope

private lateinit var locationManager: LocationManager

val trackingLocationFlow: MutableStateFlow<CurrentLocationState> = MutableStateFlow(
CurrentLocationState.UnInitialized)


init {
lifecycleScope.launch {
(context as ComponentActivity).lifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
trackingLocationFlow
.filter { LocationPermissionUtil.isPermissionGranted(context) }
.filter { it == CurrentLocationState.Prepared }
.onEach {
locationManager =
context.getSystemService(ComponentActivity.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000,
0f,
locationListener
)
}
.collect()
}
}
}


private val locationListener = object : LocationListener {
override fun onLocationChanged(locations: MutableList<Location>) {
super.onLocationChanged(locations)
Log.e("onLocationChanged", locations.toString())
}

override fun onLocationChanged(location: Location) {
val longitude = location.longitude
val latitude = location.latitude

emitFlow(CurrentLocationState.Success(
Coordinate(
longitude,
latitude
)
))

Log.e("Location", "Latitude : $latitude, Longitude : $longitude")
}

override fun onProviderEnabled(provider: String) {
super.onProviderEnabled(provider)
// provider가 사용 가능한 생태가 되는 순간 호출
}

override fun onProviderDisabled(provider: String) {
super.onProviderDisabled(provider)
// provider가 사용 불가능 상황이 되는 순간 호출
}
}

fun getLastKnownLocation(): Coordinate? {
return if (LocationPermissionUtil.isPermissionGranted(context)) {
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
?: locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)

location?.let { Coordinate(location.longitude, location.latitude) }
} else {
null
}
}

private fun emitFlow(state: CurrentLocationState) = lifecycleScope.launch {
trackingLocationFlow.emit(state)
}

fun init() {
emitFlow(CurrentLocationState.Prepared)
}
}