-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from NikolayRyabcev/dev
Спринт 25 ДЗ
- Loading branch information
Showing
11 changed files
with
312 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 6 additions & 6 deletions
12
app/src/main/java/com/example/playlistmaker/domain/player/PlayerState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
package com.example.playlistmaker.domain.player | ||
|
||
enum class PlayerState { | ||
STATE_DEFAULT, | ||
STATE_PREPARED, | ||
STATE_PLAYING, | ||
STATE_PAUSED | ||
} | ||
sealed class PlayerState { | ||
object Default : PlayerState() | ||
object Prepared : PlayerState() | ||
data class Playing (val position: String) : PlayerState() | ||
data class Paused (val position: String): PlayerState() | ||
} |
12 changes: 12 additions & 0 deletions
12
app/src/main/java/com/example/playlistmaker/services/AudioPlayerControl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.playlistmaker.services | ||
|
||
import com.example.playlistmaker.domain.player.PlayerState | ||
import kotlinx.coroutines.flow.StateFlow | ||
|
||
interface AudioPlayerControl { | ||
fun getPlayerState(): StateFlow<PlayerState> | ||
fun startPlayer() | ||
fun pausePlayer() | ||
fun provideNotificator() | ||
fun stopNotification() | ||
} |
166 changes: 163 additions & 3 deletions
166
app/src/main/java/com/example/playlistmaker/services/MusicService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,178 @@ | ||
package com.example.playlistmaker.services | ||
|
||
import android.app.Notification | ||
import android.app.NotificationChannel | ||
import android.app.NotificationManager | ||
import android.app.Service | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.content.pm.ServiceInfo | ||
import android.media.MediaPlayer | ||
import android.os.Binder | ||
import android.os.Build | ||
import android.os.IBinder | ||
import android.util.Log | ||
import androidx.core.app.NotificationCompat | ||
import androidx.core.app.ServiceCompat | ||
import com.example.playlistmaker.R | ||
import com.example.playlistmaker.domain.player.PlayerState | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.Job | ||
import kotlinx.coroutines.delay | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.launch | ||
import java.text.SimpleDateFormat | ||
import java.util.Locale | ||
|
||
class MusicService : Service() { | ||
private val binder=MusicServiceBinder() | ||
class MusicService : Service(), AudioPlayerControl { | ||
|
||
private val binder = MusicServiceBinder() | ||
|
||
private val _playerState = MutableStateFlow<PlayerState>(PlayerState.Default) | ||
private val playerServiceState = _playerState.asStateFlow() | ||
|
||
private var songUrl = "" | ||
private var trackInfo = "" | ||
|
||
private var mediaPlayer: MediaPlayer? = null | ||
|
||
private var timerJob: Job? = null | ||
|
||
private fun startTimer() { | ||
timerJob = CoroutineScope(Dispatchers.Default).launch { | ||
while (mediaPlayer?.isPlaying == true) { | ||
//if (getCurrentPlayerPosition()== "00:29") return@launch | ||
_playerState.value = PlayerState.Playing(getCurrentPlayerPosition()) | ||
delay(200L) | ||
Log.d("плеер ", "startTimer") | ||
} | ||
} | ||
} | ||
|
||
override fun onCreate() { | ||
super.onCreate() | ||
mediaPlayer = MediaPlayer() | ||
} | ||
|
||
private fun getForegroundServiceTypeConstant(): Int { | ||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | ||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK | ||
} else { | ||
0 | ||
} | ||
} | ||
|
||
override fun onBind(intent: Intent?): IBinder? { | ||
songUrl = intent?.getStringExtra("song_url") ?: "" | ||
val artist = intent?.getStringExtra("songArtist") ?: "" | ||
val track = intent?.getStringExtra("songName") ?: "" | ||
trackInfo = "$artist - $track" | ||
initMediaPlayer() | ||
return binder | ||
} | ||
|
||
//уведомления | ||
override fun provideNotificator() { | ||
createNotificationChannel() | ||
ServiceCompat.startForeground( | ||
this, | ||
SERVICE_NOTIFICATION_ID, | ||
createServiceNotification(), | ||
getForegroundServiceTypeConstant() | ||
) | ||
} | ||
|
||
override fun stopNotification() { | ||
stopForeground(true) | ||
} | ||
|
||
private fun createNotificationChannel() { | ||
Log.d("плеер", "createNotificationChannel") | ||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { | ||
Log.d("плеер", "createNotificationChannelIfBranch") | ||
return | ||
} | ||
|
||
val channel = NotificationChannel( | ||
NOTIFICATION_CHANNEL_ID, | ||
"Music service", | ||
NotificationManager.IMPORTANCE_DEFAULT | ||
) | ||
channel.description = "Service for playing music" | ||
|
||
val notificationManager = | ||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||
notificationManager.createNotificationChannel(channel) | ||
} | ||
|
||
private fun createServiceNotification(): Notification { | ||
return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) | ||
.setContentTitle("Playlist Maker") | ||
.setContentText(trackInfo) | ||
.setSmallIcon(R.drawable.ic_launcher_foreground) | ||
.setPriority(NotificationCompat.PRIORITY_DEFAULT) | ||
.setCategory(NotificationCompat.CATEGORY_SERVICE) | ||
.build() | ||
} | ||
|
||
override fun onUnbind(intent: Intent?): Boolean { | ||
releasePlayer() | ||
return super.onUnbind(intent) | ||
} | ||
|
||
private fun initMediaPlayer() { | ||
if (songUrl.isEmpty()) return | ||
mediaPlayer?.setDataSource(songUrl) | ||
mediaPlayer?.setOnPreparedListener { | ||
_playerState.value = PlayerState.Prepared | ||
} | ||
mediaPlayer?.setOnCompletionListener { | ||
_playerState.value = PlayerState.Prepared | ||
} | ||
mediaPlayer?.prepareAsync() | ||
} | ||
|
||
override fun startPlayer() { | ||
mediaPlayer?.start() | ||
_playerState.value = PlayerState.Playing(getCurrentPlayerPosition()) | ||
startTimer() | ||
} | ||
|
||
override fun pausePlayer() { | ||
mediaPlayer?.pause() | ||
timerJob?.cancel() | ||
_playerState.value = PlayerState.Paused(getCurrentPlayerPosition()) | ||
} | ||
|
||
override fun getPlayerState(): StateFlow<PlayerState> { | ||
return playerServiceState | ||
} | ||
|
||
private fun releasePlayer() { | ||
timerJob?.cancel() | ||
mediaPlayer?.stop() | ||
_playerState.value = PlayerState.Default | ||
mediaPlayer?.setOnPreparedListener(null) | ||
mediaPlayer?.setOnCompletionListener(null) | ||
mediaPlayer?.release() | ||
mediaPlayer = null | ||
} | ||
|
||
private fun getCurrentPlayerPosition(): String { | ||
return SimpleDateFormat("mm:ss", Locale.getDefault()).format(mediaPlayer?.currentPosition) | ||
?: "00:00" | ||
} | ||
|
||
inner class MusicServiceBinder : Binder() { | ||
fun getMusicService(): MusicService = this@MusicService | ||
} | ||
} | ||
|
||
private companion object { | ||
const val LOG_TAG = "MusicService" | ||
const val NOTIFICATION_CHANNEL_ID = "music_service_channel" | ||
const val SERVICE_NOTIFICATION_ID = 100 | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
app/src/main/java/com/example/playlistmaker/ui/player/buttonView/CustomViewClickListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.example.playlistmaker.ui.player.buttonView | ||
|
||
interface CustomViewClickListener { | ||
fun onViewClicked() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.