diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c80941..04f4004 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,11 @@ + + + + + diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/Adapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/Adapter.kt new file mode 100644 index 0000000..6a5b684 --- /dev/null +++ b/app/src/main/java/com/example/bcsd_android_2025_1/Adapter.kt @@ -0,0 +1,42 @@ +package com.example.bcsd_android_2025_1 + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import android.widget.Toast +import androidx.recyclerview.widget.RecyclerView + +class MusicAdapter(private val musicList: List) : + RecyclerView.Adapter() { + + class MusicViewHolder(val view: View) : RecyclerView.ViewHolder(view) { + val titleText: TextView = view.findViewById(R.id.text_list_Title) + val artistText: TextView = view.findViewById(R.id.text_list_Artist) + val durationText: TextView = view.findViewById(R.id.text_list_time) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MusicViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.music, parent, false) + return MusicViewHolder(view) + } + + override fun onBindViewHolder(holder: MusicViewHolder, position: Int) { + val music = musicList[position] + holder.titleText.text = music.title + holder.artistText.text = music.artist + + val seconds = (music.duration / 1000) % 60 + val minutes = (music.duration / (1000 * 60)) % 60 + holder.durationText.text = String.format("%02d:%02d", minutes, seconds) + + holder.view.setOnClickListener { + Toast.makeText(holder.view.context, "재생: ${music.title}", Toast.LENGTH_SHORT).show() + } + } + + override fun getItemCount(): Int = musicList.size +} + + 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..e025262 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,109 @@ package com.example.bcsd_android_2025_1 import android.os.Bundle -import androidx.activity.enableEdgeToEdge +import android.Manifest +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.provider.MediaStore +import android.provider.Settings +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.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.LinearLayoutManager class MainActivity : AppCompatActivity() { + private lateinit var recyclerView: RecyclerView + + private val requestPermission = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + val permission = getAudioPermission() + + if (isGranted) { + getAudioFile() + } else { + if (shouldShowRequestPermissionRationale(permission)) { + showPermissionRationaleDialog() + } else { + showSettingsDialog() + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + recyclerView = findViewById(R.id.recyclerView) + + requestPermission.launch(getAudioPermission()) + } + + private fun getAudioPermission(): String { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Manifest.permission.READ_MEDIA_AUDIO + } else { + Manifest.permission.READ_EXTERNAL_STORAGE + } + } + + private fun showPermissionRationaleDialog() { + AlertDialog.Builder(this) + .setTitle(getString(R.string.permission_required)) + .setMessage(getString(R.string.permission_required_music)) + .setPositiveButton(getString(R.string.permission_request)) { _, _ -> + requestPermission.launch(getAudioPermission()) + } + .setNegativeButton(getString(R.string.cancel), null) + .show() + } + + private fun showSettingsDialog() { + AlertDialog.Builder(this) + .setTitle(getString(R.string.permission_denied)) + .setMessage(getString(R.string.permission_setup_request)) + .setPositiveButton(getString(R.string.permission_move_settings)) { _, _ -> + val intent = Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", packageName, null) + ) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) + } + .setNegativeButton(getString(R.string.cancel), null) + .show() + } + + private fun getAudioFile() { + val musicList = mutableListOf() + val projection = arrayOf( + MediaStore.Audio.Media.TITLE, + MediaStore.Audio.Media.ARTIST, + MediaStore.Audio.Media.DURATION + ) + + val selection = "${MediaStore.Audio.Media.IS_MUSIC} != 0" + + contentResolver.query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + projection, selection, null, + MediaStore.Audio.Media.DEFAULT_SORT_ORDER + )?.use { cursor -> + val titleCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE) + val artistCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST) + val durationCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION) + + while (cursor.moveToNext()) { + val title = cursor.getString(titleCol) + val artist = cursor.getString(artistCol) + val duration = cursor.getLong(durationCol) + + musicList.add(Music(title, artist, duration)) + } + } + + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.adapter = MusicAdapter(musicList) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt b/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt new file mode 100644 index 0000000..c40beb7 --- /dev/null +++ b/app/src/main/java/com/example/bcsd_android_2025_1/Music.kt @@ -0,0 +1,7 @@ +package com.example.bcsd_android_2025_1 + +data class Music( + val title: String, + val artist: String, + val duration: Long +) \ 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..e9f48c2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,13 +7,9 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/music.xml b/app/src/main/res/layout/music.xml new file mode 100644 index 0000000..c437820 --- /dev/null +++ b/app/src/main/res/layout/music.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c8524cd..58d2bd3 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,5 @@ #FF000000 #FFFFFFFF + #BDBDBD \ 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..e26d22f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,11 @@ BCSD_Android_2025-1 + 재생 + 권한 필요 + 음악을 가져오기 위해 권한이 필요합니다. + 권한 요청 + 취소 + 권한이 거부됨. + 설정에서 권한을 직접 허용해주세요. + 설정으로 이동 \ No newline at end of file