Skip to content

Commit 4f2da4e

Browse files
authored
Merge pull request #100 from boostcampwm-2022/97-feature-mission-service
[PR] 미션 Foreground Service로 마이그레이션
2 parents d18c0fd + ea0f9b6 commit 4f2da4e

23 files changed

+567
-251
lines changed

presentation/src/main/AndroidManifest.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
<uses-permission android:name="android.permission.INTERNET" />
77
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
88
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
9-
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
9+
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
10+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
1011

1112
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
1213
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
@@ -33,6 +34,8 @@
3334

3435
<service android:name=".alarm.SoundService" />
3536

37+
<service android:name=".ui.mission.MissionService"/>
38+
3639
<service android:name=".alarm.SoundRestartService" />
3740

3841
<provider
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"v":"5.7.4","fr":30,"ip":0,"op":45,"w":500,"h":500,"nm":"Faild Icon","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Cross","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.214],"y":[1]},"o":{"x":[0.284],"y":[0]},"t":16,"s":[0]},{"t":33,"s":[90]}],"ix":10},"p":{"a":0,"k":[250.125,250,0],"ix":2,"l":2},"a":{"a":0,"k":[-3.875,7,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-48.75,38.25],[35,-45.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":42,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.214],"y":[1]},"o":{"x":[0.284],"y":[0]},"t":16,"s":[100]},{"t":33,"s":[0]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":-90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line-2","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-45.75,49],[38,-35]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":42,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.214],"y":[1]},"o":{"x":[0.284],"y":[0]},"t":16,"s":[0]},{"t":33,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.214],"y":[1]},"o":{"x":[0.284],"y":[0]},"t":16,"s":[0]},{"t":33,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line-1","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Red Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.316,0.316,0.667],"y":[1,1,1]},"o":{"x":[0.742,0.742,0.333],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.283,0.283,0.667],"y":[1,1,1]},"o":{"x":[0.839,0.839,0.333],"y":[0,0,0]},"t":10,"s":[111,111,100]},{"t":15,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.783,21.204],[16.229,16.229],[21.204,8.783],[22.951,0],[28.741,-19.204],[13.229,-31.935],[-6.744,-33.902],[-24.442,-24.442],[-33.902,-6.744],[-31.935,13.229],[-19.204,28.741],[0,34.567]],"o":[[-8.783,-21.205],[-16.228,-16.228],[-21.204,-8.782],[-34.566,0],[-28.742,19.203],[-13.228,31.935],[6.744,33.902],[24.442,24.442],[33.902,6.743],[31.935,-13.228],[19.204,-28.741],[0,-22.951]],"v":[[161.467,-66.882],[123.581,-123.582],[66.882,-161.468],[0,-174.771],[-97.097,-145.316],[-161.467,-66.882],[-171.413,34.096],[-123.582,123.581],[-34.096,171.413],[66.882,161.467],[145.316,97.097],[174.771,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.874509803922,0.282352941176,0.349019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}

presentation/src/main/java/com/stop/alarm/AlarmReceiver.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class AlarmReceiver : BroadcastReceiver() {
2828
val alarmStartPendingIntent = context.getActivityPendingIntent(
2929
Intent(context, AlarmActivity::class.java).apply {
3030
putExtra("ALARM_CODE", ALARM_CODE)
31-
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
31+
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
3232
},
3333
ALARM_CODE
3434
)
@@ -44,7 +44,7 @@ class AlarmReceiver : BroadcastReceiver() {
4444

4545
Intent(context, AlarmActivity::class.java).apply {
4646
putExtra("ALARM_CODE", ALARM_CODE)
47-
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
47+
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
4848
context.startActivity(this)
4949
}
5050
}

presentation/src/main/java/com/stop/di/MissionModule.kt

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.stop.model
2+
3+
enum class AlarmStatus(val text: String) {
4+
NON_EXIST("현재 등록된 막차 알림이 없습니다"), EXIST("드래그하여 등록된 막차 알림을 확인할 수 있습니다"), MISSION("진행중인 미션이 있습니다")
5+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.stop.model
22

3+
import android.os.Parcelable
4+
import kotlinx.parcelize.Parcelize
5+
6+
@Parcelize
37
data class Location(
48
val latitude: Double,
59
val longitude: Double
6-
)
10+
) : Parcelable
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.stop.model
2+
3+
enum class MissionStatus(val text: String) {
4+
BEFORE("미션 시작"), ONGOING("미션 진행중"), OVER("미션 시작")
5+
}

presentation/src/main/java/com/stop/ui/alarmsetting/AlarmSettingViewModel.kt

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import com.stop.domain.usecase.alarm.DeleteAlarmUseCase
1515
import com.stop.domain.usecase.alarm.GetAlarmUseCase
1616
import com.stop.domain.usecase.alarm.SaveAlarmUseCase
1717
import com.stop.makeFullTime
18+
import com.stop.model.AlarmStatus
19+
import com.stop.model.MissionStatus
1820
import com.stop.ui.alarmsetting.AlarmSettingFragment.Companion.ALARM_TIME
1921
import com.stop.ui.alarmsetting.AlarmSettingFragment.Companion.LAST_TIME
2022
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -41,29 +43,38 @@ class AlarmSettingViewModel @Inject constructor(
4143
private val _alarmItem = MutableStateFlow<AlarmUseCaseItem?>(null)
4244
val alarmItem: StateFlow<AlarmUseCaseItem?> = _alarmItem
4345

44-
private val _isAlarmItemNotNull = MutableStateFlow(false)
45-
val isAlarmItemNotNull: StateFlow<Boolean> = _isAlarmItemNotNull
46+
var alarmStatus = MutableStateFlow(AlarmStatus.NON_EXIST)
4647

4748
private lateinit var workerId: UUID
4849

4950
private val _lastTimeCountDown = MutableLiveData("")
5051
val lastTimeCountDown: LiveData<String> = _lastTimeCountDown
5152

52-
private val _isMissionFail = MutableLiveData(false)
53-
val isMissionFail: LiveData<Boolean> = _isMissionFail
54-
5553
fun saveAlarm(alarmUseCaseItem: AlarmUseCaseItem) {
5654
viewModelScope.launch(Dispatchers.IO) {
5755
saveAlarmUseCase.saveAlarm(alarmUseCaseItem.copy(alarmTime = alarmTime.value ?: 0, alarmMethod = alarmMethod))
5856
}
5957
}
6058

61-
fun getAlarm() {
59+
fun getAlarm(missionStatus: MissionStatus = MissionStatus.BEFORE) {
6260
viewModelScope.launch(Dispatchers.IO) {
6361
getAlarmUseCase.getAlarm().collectLatest {
6462
_alarmItem.value = it
6563

66-
_isAlarmItemNotNull.value = it != null
64+
if (it != null) {
65+
when(missionStatus){
66+
MissionStatus.BEFORE -> {
67+
alarmStatus.value = AlarmStatus.EXIST
68+
}
69+
MissionStatus.ONGOING -> {
70+
alarmStatus.value = AlarmStatus.MISSION
71+
}
72+
MissionStatus.OVER -> {
73+
alarmStatus.value = AlarmStatus.EXIST
74+
}
75+
}
76+
77+
}
6778
}
6879
}
6980
}
@@ -116,7 +127,6 @@ class AlarmSettingViewModel @Inject constructor(
116127
oldTimeMillis = System.currentTimeMillis()
117128
}
118129
}
119-
_isMissionFail.postValue(true)
120130
}
121131
}
122132

presentation/src/main/java/com/stop/ui/alarmstart/AlarmStartFragment.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.stop.alarm.SoundService
1717
import com.stop.databinding.FragmentAlarmStartBinding
1818
import com.stop.ui.alarmsetting.AlarmSettingFragment.Companion.ALARM_NOTIFICATION_HIGH_ID
1919
import com.stop.ui.alarmsetting.AlarmSettingViewModel
20+
import com.stop.ui.mission.MissionService.Companion.MISSION_CODE
2021
import kotlinx.coroutines.launch
2122

2223
class AlarmStartFragment : Fragment() {
@@ -93,6 +94,16 @@ class AlarmStartFragment : Fragment() {
9394
notificationManager.cancel(ALARM_NOTIFICATION_HIGH_ID)
9495
}
9596

97+
override fun onResume() {
98+
super.onResume()
99+
100+
requireActivity().intent.extras?.getInt("MISSION_CODE")?.let {
101+
if (it == MISSION_CODE) {
102+
binding.root.findNavController().navigate(R.id.action_alarmStartFragment_to_missionFragment)
103+
}
104+
}
105+
}
106+
96107
override fun onDestroyView() {
97108
_binding = null
98109

presentation/src/main/java/com/stop/ui/map/MapFragment.kt

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,37 @@ package com.stop.ui.map
22

33
import android.Manifest.permission
44
import android.app.NotificationManager
5+
import android.content.BroadcastReceiver
56
import android.content.Context
67
import android.content.Intent
8+
import android.content.IntentFilter
79
import android.os.Bundle
810
import android.view.LayoutInflater
911
import android.view.View
1012
import android.view.ViewGroup
1113
import androidx.activity.result.contract.ActivityResultContracts
1214
import androidx.fragment.app.Fragment
1315
import androidx.fragment.app.activityViewModels
16+
import androidx.fragment.app.viewModels
1417
import androidx.lifecycle.asLiveData
1518
import androidx.lifecycle.flowWithLifecycle
1619
import androidx.lifecycle.lifecycleScope
1720
import androidx.navigation.fragment.findNavController
1821
import com.google.android.material.bottomsheet.BottomSheetBehavior
1922
import com.skt.tmap.TMapPoint
23+
import com.stop.AlarmActivity
2024
import com.stop.R
2125
import com.stop.RouteNavGraphDirections
2226
import com.stop.alarm.SoundService
2327
import com.stop.databinding.FragmentMapBinding
28+
import com.stop.model.AlarmStatus
2429
import com.stop.model.Location
30+
import com.stop.model.MissionStatus
2531
import com.stop.ui.alarmsetting.AlarmSettingFragment
2632
import com.stop.ui.alarmsetting.AlarmSettingFragment.Companion.ALARM_MAP_CODE
2733
import com.stop.ui.alarmsetting.AlarmSettingViewModel
34+
import com.stop.ui.mission.MissionService
35+
import com.stop.ui.mission.MissionViewModel
2836
import com.stop.ui.placesearch.PlaceSearchViewModel
2937
import com.stop.ui.util.Marker
3038
import kotlinx.coroutines.launch
@@ -35,6 +43,9 @@ class MapFragment : Fragment(), MapHandler {
3543

3644
private val alarmViewModel: AlarmSettingViewModel by activityViewModels()
3745
private val placeSearchViewModel: PlaceSearchViewModel by activityViewModels()
46+
private val missionViewModel: MissionViewModel by viewModels()
47+
48+
private lateinit var missionServiceIntent: Intent
3849

3950
private lateinit var tMap: MapTMap
4051
private var mapUIVisibility = View.GONE
@@ -56,6 +67,7 @@ class MapFragment : Fragment(), MapHandler {
5667
initTMap()
5768
initBottomSheetBehavior()
5869
initBottomSheetView()
70+
setBroadcastReceiver()
5971
}
6072

6173
override fun alertTMapReady() {
@@ -78,6 +90,7 @@ class MapFragment : Fragment(), MapHandler {
7890
binding.lifecycleOwner = viewLifecycleOwner
7991
binding.alarmViewModel = alarmViewModel
8092
binding.placeSearchViewModel = placeSearchViewModel
93+
binding.missionViewModel = missionViewModel
8194
binding.fragment = this@MapFragment
8295
}
8396

@@ -155,8 +168,18 @@ class MapFragment : Fragment(), MapHandler {
155168

156169
val behavior = BottomSheetBehavior.from(binding.layoutHomeBottomSheet)
157170

158-
alarmViewModel.isAlarmItemNotNull.asLiveData().observe(viewLifecycleOwner) {
159-
behavior.isDraggable = it
171+
alarmViewModel.alarmStatus.asLiveData().observe(viewLifecycleOwner) { alarmStatus ->
172+
when (alarmStatus) {
173+
AlarmStatus.NON_EXIST -> {
174+
behavior.isDraggable = false
175+
}
176+
AlarmStatus.EXIST -> {
177+
behavior.isDraggable = true
178+
}
179+
AlarmStatus.MISSION -> {
180+
behavior.isDraggable = true
181+
}
182+
}
160183
}
161184

162185
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
@@ -183,9 +206,35 @@ class MapFragment : Fragment(), MapHandler {
183206
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
184207
requireContext().stopService(intent)
185208
SoundService.normalExit = true
209+
210+
setMissionOver()
186211
}
187212
}
188213

214+
private fun setMissionOver() {
215+
missionServiceIntent = Intent(requireActivity(), MissionService::class.java)
216+
requireActivity().stopService(missionServiceIntent)
217+
missionViewModel.missionStatus.value = MissionStatus.BEFORE
218+
alarmViewModel.alarmStatus.value = AlarmStatus.NON_EXIST
219+
}
220+
221+
private fun setBroadcastReceiver() {
222+
val intentFilter = IntentFilter().apply {
223+
addAction(MissionService.MISSION_STATUS)
224+
}
225+
226+
val receiver = object : BroadcastReceiver() {
227+
override fun onReceive(context: Context?, intent: Intent?) {
228+
if (intent?.getBooleanExtra(MissionService.MISSION_STATUS, false) == true) {
229+
missionViewModel.missionStatus.value = MissionStatus.ONGOING
230+
alarmViewModel.alarmStatus.value = AlarmStatus.MISSION
231+
}
232+
}
233+
}
234+
235+
requireActivity().registerReceiver(receiver, intentFilter)
236+
}
237+
189238
private fun observeClickPlace() {
190239
placeSearchViewModel.clickPlaceUseCaseItem.observe(viewLifecycleOwner) { event ->
191240
event.getContentIfNotHandled()?.let { clickPlace ->
@@ -204,7 +253,7 @@ class MapFragment : Fragment(), MapHandler {
204253
}
205254

206255
private fun observeClickCurrentLocation() {
207-
lifecycleScope.launch {
256+
viewLifecycleOwner.lifecycleScope.launch {
208257
placeSearchViewModel.clickCurrentLocation
209258
.flowWithLifecycle(viewLifecycleOwner.lifecycle)
210259
.collect {
@@ -291,7 +340,11 @@ class MapFragment : Fragment(), MapHandler {
291340
}
292341

293342
fun setMissionStart() {
294-
// TODO 미션으로 보내는 작업해야함
343+
Intent(requireContext(), AlarmActivity::class.java).apply {
344+
putExtra("MISSION_CODE", MissionService.MISSION_CODE)
345+
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
346+
startActivity(this)
347+
}
295348
}
296349

297350
companion object {

0 commit comments

Comments
 (0)