diff --git a/app/build.gradle b/app/build.gradle index 2b3280c..42ccca5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,6 +16,10 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + androidExtensions { + experimental = true + } + buildTypes { release { minifyEnabled false @@ -34,4 +38,5 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + implementation 'com.google.android.material:material:1.2.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 94e0e73..e6d6b9e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + - diff --git a/app/src/main/aidl/ISongAidlInterface.aidl b/app/src/main/aidl/ISongAidlInterface.aidl new file mode 100644 index 0000000..6b6326b --- /dev/null +++ b/app/src/main/aidl/ISongAidlInterface.aidl @@ -0,0 +1,26 @@ +// ISongAidlInterface.aidl +package com.example.myapplication; + +// Declare any non-default types here with import statements + +interface ISongAidlInterface { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void play(); + void pause(); + boolean isPlaying(); + boolean isMPReleased(); + int getDuration(); + int getCurrentPosition(); + void changeTime(int time); + void playNext(); + void playPrev(); + + Song getSong(); + void setCurrentSong(int position); + void setCurrentSongFromBundle(in Bundle bundle); +} + +parcelable Song; diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt index 6ca80fa..5115ecf 100644 --- a/app/src/main/java/com/example/myapplication/MainActivity.kt +++ b/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -1,12 +1,54 @@ package com.example.myapplication +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.os.IBinder +import android.util.Log +import androidx.core.app.NotificationCompat +import com.example.myapplication.screens.songsList.SongsListFragment +import com.example.myapplication.service.SongService class MainActivity : AppCompatActivity() { + var songService: ISongAidlInterface? = null + lateinit var builder: NotificationCompat.Builder + val CHANNEL_ID = "playerChannel" + + private val aidlConnection = object : ServiceConnection { + + override fun onServiceConnected(className: ComponentName, service: IBinder) { + songService = ISongAidlInterface.Stub.asInterface(service) + supportFragmentManager.beginTransaction(). + replace(R.id.frameLayout, SongsListFragment()).commit() + } + + override fun onServiceDisconnected(className: ComponentName) { + songService = null + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } + + override fun onStart() { + super.onStart() + val intent = + Intent(this, SongService::class.java) + bindService(intent, aidlConnection, Context.BIND_AUTO_CREATE) + } + + override fun onDestroy() { + super.onDestroy() + Log.e("LOG_TAG", "MainActivity onServiceDisconnected") + songService?.let { + unbindService(aidlConnection) + songService = null + } + + } } diff --git a/app/src/main/java/com/example/myapplication/Song.kt b/app/src/main/java/com/example/myapplication/Song.kt new file mode 100644 index 0000000..4462cef --- /dev/null +++ b/app/src/main/java/com/example/myapplication/Song.kt @@ -0,0 +1,44 @@ +package com.example.myapplication + +import android.os.Parcel +import android.os.Parcelable +import androidx.annotation.DrawableRes +import androidx.annotation.RawRes + +data class Song( + var author: String = "", + var name: String = "", + @DrawableRes var photoId: Int = 0, + @RawRes var songId: Int = 0 +) : Parcelable { + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Song { + return Song(parcel) + } + + override fun newArray(size: Int): Array { + return Array(size) { Song() } + } + } + + private constructor(inParcel: Parcel) : this() { + readFromParcel(inParcel) + } + + private fun readFromParcel(inParcel: Parcel) { + author = inParcel.readString() ?: "" + name = inParcel.readString() ?: "" + songId = inParcel.readInt() ?: 0 + photoId = inParcel.readInt() ?: 0 + } + + override fun writeToParcel(outParcel: Parcel, flags: Int) { + outParcel.writeString(author) + outParcel.writeString(name) + outParcel.writeInt(songId) + outParcel.writeInt(photoId) + } + + override fun describeContents(): Int = 0 +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/adapters/SongAdapter.kt b/app/src/main/java/com/example/myapplication/adapters/SongAdapter.kt new file mode 100644 index 0000000..e1ebc03 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/adapters/SongAdapter.kt @@ -0,0 +1,44 @@ +package com.example.myapplication.adapters + + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.myapplication.Song +import com.example.myapplication.R +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.item_song.* + + +class SongAdapter ( + private var list: ArrayList, + private val fragmentLambda: (View, Int) -> Unit +) : RecyclerView.Adapter() { + + inner class SongViewHolder( + override val containerView: View + ): RecyclerView.ViewHolder(containerView), LayoutContainer { + + fun bind(song: Song, position: Int) { + with(song) { + tv_sm_title.text = name + tv_sm_author.text = author + iv_sm_album.setImageResource(song.photoId) + } + + itemView.setOnClickListener{fragmentLambda(itemView,position)} + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder { + return SongViewHolder(LayoutInflater.from(parent.context). + inflate(R.layout.item_song, parent, false)) + } + + override fun onBindViewHolder(holder: SongViewHolder, position: Int) { + holder.bind(list[position], position) + } + + override fun getItemCount(): Int = list.size +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/repository/SongRepository.kt b/app/src/main/java/com/example/myapplication/repository/SongRepository.kt new file mode 100644 index 0000000..6ad6f2a --- /dev/null +++ b/app/src/main/java/com/example/myapplication/repository/SongRepository.kt @@ -0,0 +1,14 @@ +package com.example.myapplication.repository + +import com.example.myapplication.Song +import com.example.myapplication.R + +object SongRepository { + val songsList: List = arrayListOf( + Song("SLAVA","Снова я напиваюсь", R.drawable.straus, R.raw.again_drink), + Song("Dora","Втюрилась", R.drawable.straus, R.raw.dora), + Song("Нурминчик","Валим валим на гелике", R.drawable.straus, R.raw.valim), + Song("Нурминчик","Ауф", R.drawable.straus, R.raw.auf), + Song("Кто-то","Арабская", R.drawable.straus, R.raw.arabskay) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/screens/song/SongFragment.kt b/app/src/main/java/com/example/myapplication/screens/song/SongFragment.kt new file mode 100644 index 0000000..f387830 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/screens/song/SongFragment.kt @@ -0,0 +1,85 @@ +package com.example.myapplication.screens.song + +import android.os.Bundle +import android.os.Handler +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.SeekBar +import com.example.myapplication.ISongAidlInterface +import com.example.myapplication.MainActivity +import com.example.myapplication.R +import com.example.myapplication.Song +import kotlinx.android.synthetic.main.fragment_song.* + +class SongFragment : Fragment() { + var service: ISongAidlInterface? = null + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_song, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val activity = (activity as MainActivity?) + service = activity?.songService + changeUI(service?.song) + initialiseSeekBar() + + + iv_play.setOnClickListener { + if (service?.isPlaying == true) { + iv_play.setImageResource(R.drawable.ic_play) + service?.pause() + } else if (service?.isPlaying == false) { + iv_play.setImageResource(R.drawable.ic_pause) + service?.play() + } + } + iv_next.setOnClickListener { + service?.playNext() + changeUI(service?.song) + } + iv_prev.setOnClickListener { + service?.playPrev() + changeUI(service?.song) + } + seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { + if (p2) { + service?.changeTime(p1) + } + } + + override fun onStartTrackingTouch(p0: SeekBar?) { + } + + override fun onStopTrackingTouch(p0: SeekBar?) { + } + }) + } + + private fun changeUI(song: Song?) { + song?.photoId?.let { iv_album.setImageResource(it) } + tv_author.text = song?.author + tv_name.text = song?.name + + } + + private fun initialiseSeekBar() { + seekBar.max = service!!.duration + var handler: Handler = Handler() + handler.postDelayed(object : Runnable { + override fun run() { + seekBar.progress = service?.currentPosition!! + handler.postDelayed(this, 1000) + } + }, 0) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/screens/songsList/SongsListFragment.kt b/app/src/main/java/com/example/myapplication/screens/songsList/SongsListFragment.kt new file mode 100644 index 0000000..7c286fb --- /dev/null +++ b/app/src/main/java/com/example/myapplication/screens/songsList/SongsListFragment.kt @@ -0,0 +1,53 @@ +package com.example.myapplication.screens.songsList + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.myapplication.ISongAidlInterface +import com.example.myapplication.MainActivity +import com.example.myapplication.Song +import com.example.myapplication.adapters.SongAdapter +import com.example.myapplication.repository.SongRepository +import com.example.myapplication.screens.song.SongFragment +import com.example.myapplication.R +import kotlinx.android.synthetic.main.fragment_songs_list.* + +class SongsListFragment : Fragment() { + + private var adapter: SongAdapter? = null + var service: ISongAidlInterface? = null + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.fragment_songs_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val activity = (activity as MainActivity?) + service = activity?.songService + adapter = SongAdapter(SongRepository.songsList as ArrayList) { item, position -> + val transaction = activity?.supportFragmentManager?.beginTransaction() + + transaction?.addToBackStack(null) + item.setOnClickListener { + if (service?.isMPReleased == true + || service?.song != SongRepository.songsList[position] + ) { + service?.setCurrentSong(position) + } + + transaction?.replace( + R.id.frameLayout, + SongFragment() + )?.commit() + + } + } + rv_song.adapter = adapter + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/service/SongService.kt b/app/src/main/java/com/example/myapplication/service/SongService.kt new file mode 100644 index 0000000..c80d8ee --- /dev/null +++ b/app/src/main/java/com/example/myapplication/service/SongService.kt @@ -0,0 +1,94 @@ +package com.example.myapplication.service + +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.os.Bundle +import android.os.IBinder +import com.example.myapplication.ISongAidlInterface +import com.example.myapplication.Song +import com.example.myapplication.repository.SongRepository + +class SongService : Service() { + private var mediaPlayer: MediaPlayer = MediaPlayer() + private var isPlayerReleased = true + + private lateinit var serviceSong: Song + + private val mBinder: ISongAidlInterface.Stub = object : ISongAidlInterface.Stub() { + + override fun play() { + mediaPlayer.start() + } + + override fun pause() { + mediaPlayer.pause() + } + + override fun isPlaying() = mediaPlayer.isPlaying + + override fun isMPReleased(): Boolean = isPlayerReleased + + override fun getSong(): Song? { + return serviceSong + } + + override fun getDuration(): Int { + return mediaPlayer.duration + } + + override fun getCurrentPosition(): Int { + return mediaPlayer.currentPosition + } + + override fun changeTime(time: Int) { + mediaPlayer.seekTo(time) + } + + override fun playNext() { + var position = SongRepository.songsList.indexOf(song) + position = if (position + 1 == SongRepository.songsList.size) 0 else position + 1 + setCurrentSong(position) + } + + override fun playPrev() { + var position = SongRepository.songsList.indexOf(song) + position = if (position == 0) SongRepository.songsList.size - 1 else position - 1 + setCurrentSong(position) + } + + override fun setCurrentSong(position: Int) { + serviceSong = SongRepository.songsList[position] + playSong(serviceSong) + } + + override fun setCurrentSongFromBundle(bundle: Bundle) { + with(bundle) { + classLoader = this@SongService.classLoader + getParcelable("key_song").also { + } + } + } + } + + + override fun onBind(intent: Intent): IBinder = mBinder + + override fun onDestroy() { + super.onDestroy() + mediaPlayer.release() + } + + private fun playSong(song: Song) { + if (mediaPlayer.isPlaying) mediaPlayer.stop() + mediaPlayer = MediaPlayer.create(applicationContext, song.songId) + isPlayerReleased = false + mediaPlayer.run { + start() + setOnCompletionListener { + stop() // or call next() for change track + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/p1.jpg b/app/src/main/res/drawable-v24/p1.jpg new file mode 100644 index 0000000..b7b4b17 Binary files /dev/null and b/app/src/main/res/drawable-v24/p1.jpg differ diff --git a/app/src/main/res/drawable-v24/p2.jpg b/app/src/main/res/drawable-v24/p2.jpg new file mode 100644 index 0000000..c447606 Binary files /dev/null and b/app/src/main/res/drawable-v24/p2.jpg differ diff --git a/app/src/main/res/drawable-v24/p3.jpg b/app/src/main/res/drawable-v24/p3.jpg new file mode 100644 index 0000000..8f25b78 Binary files /dev/null and b/app/src/main/res/drawable-v24/p3.jpg differ diff --git a/app/src/main/res/drawable-v24/p4.jpg b/app/src/main/res/drawable-v24/p4.jpg new file mode 100644 index 0000000..a09f367 Binary files /dev/null and b/app/src/main/res/drawable-v24/p4.jpg differ diff --git a/app/src/main/res/drawable-v24/p5.jpg b/app/src/main/res/drawable-v24/p5.jpg new file mode 100644 index 0000000..ea1d987 Binary files /dev/null and b/app/src/main/res/drawable-v24/p5.jpg differ diff --git a/app/src/main/res/drawable/ic_next.xml b/app/src/main/res/drawable/ic_next.xml new file mode 100644 index 0000000..115a50c --- /dev/null +++ b/app/src/main/res/drawable/ic_next.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause.xml b/app/src/main/res/drawable/ic_pause.xml new file mode 100644 index 0000000..b879cb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml new file mode 100644 index 0000000..1b66071 --- /dev/null +++ b/app/src/main/res/drawable/ic_play.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_previous.xml b/app/src/main/res/drawable/ic_previous.xml new file mode 100644 index 0000000..530597c --- /dev/null +++ b/app/src/main/res/drawable/ic_previous.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4fc2444..08a0465 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,13 +6,9 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_song_list.xml b/app/src/main/res/layout/activity_song_list.xml new file mode 100644 index 0000000..412beeb --- /dev/null +++ b/app/src/main/res/layout/activity_song_list.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_song.xml b/app/src/main/res/layout/fragment_song.xml new file mode 100644 index 0000000..1986ba1 --- /dev/null +++ b/app/src/main/res/layout/fragment_song.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_songs_list.xml b/app/src/main/res/layout/fragment_songs_list.xml new file mode 100644 index 0000000..08a7b7b --- /dev/null +++ b/app/src/main/res/layout/fragment_songs_list.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_song.xml b/app/src/main/res/layout/item_song.xml new file mode 100644 index 0000000..bc9e6e0 --- /dev/null +++ b/app/src/main/res/layout/item_song.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/song_item.xml b/app/src/main/res/layout/song_item.xml new file mode 100644 index 0000000..178bd78 --- /dev/null +++ b/app/src/main/res/layout/song_item.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/a4.mp3 b/app/src/main/res/raw/a4.mp3 new file mode 100644 index 0000000..0d0499c Binary files /dev/null and b/app/src/main/res/raw/a4.mp3 differ diff --git a/app/src/main/res/raw/again_drink.mp3 b/app/src/main/res/raw/again_drink.mp3 new file mode 100644 index 0000000..7635bd7 Binary files /dev/null and b/app/src/main/res/raw/again_drink.mp3 differ diff --git a/app/src/main/res/raw/arabskay.mp3 b/app/src/main/res/raw/arabskay.mp3 new file mode 100644 index 0000000..6d16ee4 Binary files /dev/null and b/app/src/main/res/raw/arabskay.mp3 differ diff --git a/app/src/main/res/raw/auf.mp3 b/app/src/main/res/raw/auf.mp3 new file mode 100644 index 0000000..930c2fb Binary files /dev/null and b/app/src/main/res/raw/auf.mp3 differ diff --git a/app/src/main/res/raw/dora.mp3 b/app/src/main/res/raw/dora.mp3 new file mode 100644 index 0000000..79b4c9e Binary files /dev/null and b/app/src/main/res/raw/dora.mp3 differ diff --git a/app/src/main/res/raw/pobolelo.mp3 b/app/src/main/res/raw/pobolelo.mp3 new file mode 100644 index 0000000..df1415d Binary files /dev/null and b/app/src/main/res/raw/pobolelo.mp3 differ diff --git a/app/src/main/res/raw/problema.mp3 b/app/src/main/res/raw/problema.mp3 new file mode 100644 index 0000000..b74b481 Binary files /dev/null and b/app/src/main/res/raw/problema.mp3 differ diff --git a/app/src/main/res/raw/time_shoot.mp3 b/app/src/main/res/raw/time_shoot.mp3 new file mode 100644 index 0000000..7315698 Binary files /dev/null and b/app/src/main/res/raw/time_shoot.mp3 differ diff --git a/app/src/main/res/raw/valim.mp3 b/app/src/main/res/raw/valim.mp3 new file mode 100644 index 0000000..b9f6c16 Binary files /dev/null and b/app/src/main/res/raw/valim.mp3 differ