diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..c4e4683
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+BCSD_Android_2025-1
\ No newline at end of file
diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..639c779
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..c224ad5
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..f7608ed
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21__8_40__Changes_.xml b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21__8_40__Changes_.xml
new file mode 100644
index 0000000..bdc777e
--- /dev/null
+++ b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21__8_40__Changes_.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git "a/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21_\354\230\244\355\233\204_8_40_[Changes]/shelved.patch" "b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21_\354\230\244\355\233\204_8_40_[Changes]/shelved.patch"
new file mode 100644
index 0000000..6ba94fa
--- /dev/null
+++ "b/.idea/shelf/Uncommitted_changes_before_Checkout_at_2025-06-21_\354\230\244\355\233\204_8_40_[Changes]/shelved.patch"
@@ -0,0 +1,54 @@
+Index: app/src/main/java/com/example/bcsd_android_2025_1/NotificationReceiver.kt
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>package com.example.bcsd_android_2025_1\r\n\r\nimport android.content.BroadcastReceiver\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport android.app.NotificationManager\r\n\r\nclass NotificationReceiver : BroadcastReceiver() {\r\n override fun onReceive(context: Context, intent: Intent) {\r\n if (intent.action == \"ACTION_CLOSE_NOTIFICATION\") {\r\n val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\r\n manager.cancel(1001)\r\n }\r\n }\r\n}
+===================================================================
+diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/NotificationReceiver.kt b/app/src/main/java/com/example/bcsd_android_2025_1/NotificationReceiver.kt
+--- a/app/src/main/java/com/example/bcsd_android_2025_1/NotificationReceiver.kt (revision 4f6ece16be6f02f2dbafa328f24458f0f7c007d0)
++++ b/app/src/main/java/com/example/bcsd_android_2025_1/NotificationReceiver.kt (date 1748276211662)
+@@ -12,4 +12,5 @@
+ manager.cancel(1001)
+ }
+ }
+-}
+\ No newline at end of file
++}
++
+Index: .idea/deploymentTargetSelector.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
+===================================================================
+diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
+--- a/.idea/deploymentTargetSelector.xml (revision 4f6ece16be6f02f2dbafa328f24458f0f7c007d0)
++++ b/.idea/deploymentTargetSelector.xml (date 1748343144801)
+@@ -2,10 +2,10 @@
+
+
+
+-
++
+
+
+-
++
+
+
+
+Index: .idea/vcs.xml
+IDEA additional info:
+Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
+<+>\r\n\r\n \r\n \r\n \r\n
+===================================================================
+diff --git a/.idea/vcs.xml b/.idea/vcs.xml
+--- a/.idea/vcs.xml (revision 4f6ece16be6f02f2dbafa328f24458f0f7c007d0)
++++ b/.idea/vcs.xml (date 1748343115810)
+@@ -1,6 +1,6 @@
+
+
+
+-
++
+
+
+\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5791375..ff0bc0a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -36,7 +36,7 @@ android {
}
dependencies {
-
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c80941..ac9be35 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,15 @@
+
+
+
+
+
+
+
+
+
+
@@ -23,4 +38,5 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/AudioAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/AudioAdapter.kt
new file mode 100644
index 0000000..7a3deca
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/AudioAdapter.kt
@@ -0,0 +1,64 @@
+package com.example.bcsd_android_2025_1
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+
+class AudioAdapter : RecyclerView.Adapter(){
+
+
+ private val items = mutableListOf()
+
+ fun submitList(newList: List) {
+ items.clear()
+ items.addAll(newList)
+ notifyDataSetChanged()
+ }
+
+ inner class AudioViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val titleTextView: TextView = itemView.findViewById(R.id.tv_item_title)
+ val artistTextView: TextView = itemView.findViewById(R.id.tv_item_artist)
+ val timeTextView: TextView = itemView.findViewById(R.id.tv_item_time)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudioViewHolder {
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.item, parent, false)
+ return AudioViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: AudioViewHolder, position: Int) {
+ val item = items[position]
+ holder.titleTextView.text = item.name
+ holder.artistTextView.text = item.artist
+
+ val totalTime = item.duration/1000
+ val hours = totalTime/3600
+ val minutes = (totalTime%3600)/60
+ val seconds = totalTime%60
+ if (hours > 0){
+ holder.timeTextView.text = String.format("%d:%02d:%02d", hours, minutes, seconds)
+ } else {
+ holder.timeTextView.text = String.format("%d:%02d", minutes, seconds)
+ }
+
+ holder.itemView.setOnClickListener {
+ val context = holder.itemView.context
+ val intent = Intent(context, AudioPlayer::class.java).apply{
+ putExtra("AUDIO_URI",item.uri)
+ putExtra("AUDIO_TITLE",item.name)
+ }
+ ContextCompat.startForegroundService(context, intent)
+ }
+
+ }
+
+ override fun getItemCount(): Int = items.size
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/AudioListManager.kt b/app/src/main/java/com/example/bcsd_android_2025_1/AudioListManager.kt
new file mode 100644
index 0000000..598fa83
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/AudioListManager.kt
@@ -0,0 +1,62 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.Application
+import android.content.ContentUris
+import android.provider.MediaStore.Audio.Media
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+
+class AudioListManager(application: Application) : AndroidViewModel(application) {
+ private val audioListIn = MutableLiveData>()
+ val audioListObserve: LiveData> get() = audioListIn
+
+ fun loadAudioFiles() {
+ viewModelScope.launch(Dispatchers.IO) {
+ val list = mutableListOf()
+ val resolver = getApplication().contentResolver
+
+ val projection = arrayOf(
+ Media._ID,
+ Media.DISPLAY_NAME,
+ Media.ARTIST,
+ Media.DURATION
+ )
+
+ val selection= "${Media.IS_MUSIC} != 0 AND ${Media.DURATION} > 0"
+ val selectionArgs: Array? = null
+
+ val sortOrder = "${Media.DATE_ADDED} DESC"
+
+ resolver.query(
+ Media.EXTERNAL_CONTENT_URI,
+ projection,
+ selection,
+ selectionArgs,
+ sortOrder
+ )?.use { cursor ->
+ val idColumn = cursor.getColumnIndexOrThrow(Media._ID)
+ val nameColumn = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME)
+ val artistColumn = cursor.getColumnIndexOrThrow(Media.ARTIST)
+ val durationColumn = cursor.getColumnIndexOrThrow(Media.DURATION)
+
+ while (cursor.moveToNext()) {
+ val id = cursor.getLong(idColumn)
+ val name = cursor.getString(nameColumn)
+ val artists = cursor.getString(artistColumn)
+ val duration = cursor.getLong(durationColumn)
+ val uri = ContentUris.withAppendedId(Media.EXTERNAL_CONTENT_URI, id)
+
+ list.add(MainActivity.AudioItem(id, name, artists, duration, uri))
+
+ }
+ }
+
+ audioListIn.postValue(list)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/AudioPlayer.kt b/app/src/main/java/com/example/bcsd_android_2025_1/AudioPlayer.kt
new file mode 100644
index 0000000..afe035e
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/AudioPlayer.kt
@@ -0,0 +1,92 @@
+package com.example.bcsd_android_2025_1
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.media.MediaPlayer
+import android.net.Uri
+import android.os.Build
+import android.os.IBinder
+import androidx.core.app.NotificationCompat
+
+
+@Suppress("DEPRECATION")
+class AudioPlayer : Service() {
+
+ private lateinit var mediaPlayer: MediaPlayer
+ private var currentAudioTitle: String = ""
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ val audioUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent?.getParcelableExtra("AUDIO_URI", Uri::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ intent?.getParcelableExtra("AUDIO_URI")
+
+ }
+ currentAudioTitle = intent?.getStringExtra("AUDIO_TITLE") ?: "음악"
+
+ audioUri?.let {
+ mediaPlayer = MediaPlayer.create(this, audioUri)
+ mediaPlayer.setOnCompletionListener {
+ stopForeground(true)
+ }
+ mediaPlayer.start()
+ showNotification(currentAudioTitle)
+ nowPlaying(currentAudioTitle)
+ }
+ return START_NOT_STICKY
+ }
+
+ private fun showNotification(title: String) {
+ val channelId = "music_channel"
+ val channelName = "음악 재생 채널"
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channel = NotificationChannel(
+ channelId,
+ channelName,
+ NotificationManager.IMPORTANCE_LOW
+ )
+ val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.createNotificationChannel(channel)
+ }
+
+
+ val intent = Intent(this, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ this, 0, intent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+
+
+
+ val notification = NotificationCompat.Builder(this, channelId)
+ .setContentTitle("재생 중")
+ .setContentText(title)
+ .setSmallIcon(R.drawable.ic_launcher_background)
+ .setContentIntent(pendingIntent)
+ .setOngoing(true)
+ .build()
+
+ startForeground(1, notification)
+ }
+
+ override fun onDestroy() {
+ if (::mediaPlayer.isInitialized){
+ mediaPlayer.release()
+ }
+ super.onDestroy()
+ }
+
+ override fun onBind(p0: Intent?): IBinder? = null
+
+ private fun nowPlaying(title: String) {
+ val intent = Intent(MainActivity.NOW_PLAYING)
+ intent.putExtra("AUDIO_TITLE",title)
+ sendBroadcast(intent)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
index 3ffa0eb..381a5aa 100644
--- a/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
@@ -1,14 +1,163 @@
package com.example.bcsd_android_2025_1
+import android.Manifest
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
+import android.provider.Settings
+import android.view.View
+import android.widget.Button
+import android.widget.TextView
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
+import androidx.core.app.ActivityCompat
+import androidx.core.net.toUri
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
+
+ private lateinit var permissionName: String
+ private lateinit var audioAdapter: AudioAdapter
+
+ private lateinit var tvMain : TextView
+ private lateinit var btnMain : Button
+
+ private lateinit var audioListManager : AudioListManager
+
+ private lateinit var playingAudioAdapter : PlayingAudioAdapter
+
+ companion object {
+ const val NOW_PLAYING = "nowPlaying"
+ }
+
+ private val requestPermission =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+ when (isGranted) {
+ true -> getAudioFile()
+ else -> {
+ when (shouldShowRequestPermissionRationale(permissionName)) {
+ true -> permissionDialog(true)
+ else -> permissionDialog(false)
+ }
+ }
+ }
+ }
+
+ private val nowPlayingReceive = object : BroadcastReceiver() {
+ override fun onReceive(p0: Context?, p1: Intent?) {
+ val title = p1?.getStringExtra("AUDIO_TITLE") ?: return
+ val id = p1.getLongExtra("AUDIO_ID", -1)
+ val artist = p1.getStringExtra("AUDIO_ARTIST") ?: "알 수 없음"
+ val duration = p1.getLongExtra("AUDIO_DURATION",0)
+ val uri = p1.getStringExtra("AUDIO_URI")?.toUri() ?: return
+
+ val item = AudioItem(id, title, artist, duration, uri)
+ playingAudioAdapter.setItem(item)
+
+ }
+ }
+
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+
+ permissionName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ Manifest.permission.READ_MEDIA_AUDIO
+ } else {
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS),
+ 1001
+ )
+ }
+ }
+
+//초기화
+ playingAudioAdapter = PlayingAudioAdapter()
+ audioAdapter =AudioAdapter()
+ audioListManager = AudioListManager(application)
+//리사이클(전체)
+ val recyclerView = findViewById(R.id.rv_main)
+ recyclerView.adapter = audioAdapter
+ recyclerView.layoutManager = LinearLayoutManager(this)
+//리사이클(현재)
+ val playingRecyclerView = findViewById(R.id.rv_playing)
+ playingRecyclerView.adapter = playingAudioAdapter
+ playingRecyclerView.layoutManager = LinearLayoutManager(this)
+
+ requestPermission.launch(permissionName)
+
+ tvMain = findViewById(R.id.tv_main)
+ btnMain = findViewById(R.id.btn_main)
+
+ audioListManager.audioListObserve.observe(this) {list ->
+ audioAdapter.submitList(list)
+ }
+
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ registerReceiver(nowPlayingReceive, IntentFilter(NOW_PLAYING), RECEIVER_NOT_EXPORTED)
+ }
}
+
+ override fun onPause() {
+ super.onPause()
+ unregisterReceiver(nowPlayingReceive)
+ }
+
+ private fun permissionDialog(isShowRationale: Boolean) {
+ if (isShowRationale) {
+ AlertDialog.Builder(this)
+ .setTitle(R.string.tv_main)
+ .setPositiveButton(R.string.alert_btn_positive){
+ _, _ ->
+ requestPermission.launch(permissionName)
+ }
+ .setNegativeButton(R.string.alert_btn_negative, null)
+ .show()
+
+ }
+
+ tvMain.visibility = View.VISIBLE
+ btnMain.visibility = View.VISIBLE
+
+ btnMain.setOnClickListener {
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = "package:$packageName".toUri()
+ }
+ startActivity(intent)
+ }
+ }
+
+ private fun getAudioFile() {
+ tvMain.visibility = View.GONE
+ btnMain.visibility = View.GONE
+ audioListManager.loadAudioFiles()
+ }
+
+ data class AudioItem(
+ val id: Long,
+ val name: String,
+ val artist: String,
+ val duration: Long,
+ val uri: Uri
+ )
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/PlayingAudioAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/PlayingAudioAdapter.kt
new file mode 100644
index 0000000..39949ba
--- /dev/null
+++ b/app/src/main/java/com/example/bcsd_android_2025_1/PlayingAudioAdapter.kt
@@ -0,0 +1,38 @@
+package com.example.bcsd_android_2025_1
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+
+class PlayingAudioAdapter : RecyclerView.Adapter(){
+
+
+ private var playItem : MainActivity.AudioItem? = null
+
+ fun setItem(item: MainActivity.AudioItem){
+ playItem = item
+ notifyDataSetChanged()
+ }
+
+ inner class PlayingAudioHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ val playTitle = itemView.findViewById(R.id.tv_item_title)
+ val playArtist = itemView.findViewById(R.id.tv_item_artist)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlayingAudioHolder {
+ val view = LayoutInflater.from(parent.context)
+ .inflate(R.layout.item, parent, false)
+ return PlayingAudioHolder(view)
+ }
+
+ override fun getItemCount(): Int = if (playItem != null) 1 else 0
+
+ override fun onBindViewHolder(holder: PlayingAudioHolder, position: Int) {
+ playItem?.let {
+ holder.playTitle.text = it.name
+ holder.playArtist.text = it.artist
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 311f3cb..c3be349 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -7,13 +7,42 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
+
+
+
+
+
+
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ android:layout_marginTop="32dp"/>
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item.xml b/app/src/main/res/layout/item.xml
new file mode 100644
index 0000000..94a29bb
--- /dev/null
+++ b/app/src/main/res/layout/item.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c6c4daf..6d4daad 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,15 @@
- BCSD_Android_2025-1
+ BCSD_Android_2025–1
+
+ Hello blank fragment
+ 권한이 필요합니다.
+ nowPlaying
+ 설정 열기
+ 제목
+ 가수
+ 분:초
+ 예
+ 아니요
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 283fec9..e6d8d96 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,12 +6,14 @@ junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
+lifecycleViewmodelKtx = "2.9.1"
material = "1.12.0"
activity = "1.9.3"
constraintlayout = "2.2.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }