From db55bf043d955a12f3866e7ca95f08c9597f16b6 Mon Sep 17 00:00:00 2001 From: Sangjin Kim Date: Mon, 23 Jun 2025 14:15:31 +0900 Subject: [PATCH 1/2] =?UTF-8?q?9=EC=A3=BC=EC=B0=A8=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.name | 1 + .idea/AndroidProjectSystem.xml | 6 + .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 10 ++ .idea/gradle.xml | 19 +++ .idea/kotlinc.xml | 6 + .idea/migrations.xml | 10 ++ .idea/misc.xml | 7 + .idea/runConfigurations.xml | 17 ++ .idea/vcs.xml | 6 + app/build.gradle.kts | 1 - app/src/main/AndroidManifest.xml | 3 + .../example/bcsd_android_2025_1/ListData.kt | 6 + .../bcsd_android_2025_1/MainActivity.kt | 158 +++++++++++++++++- .../RecyclerViewAdapter.kt | 65 +++++++ .../drawable/album_image_default_aespa.png | Bin 0 -> 12244 bytes app/src/main/res/layout/activity_main.xml | 30 +++- app/src/main/res/layout/item_recyclerview.xml | 47 ++++++ app/src/main/res/values/colors.xml | 5 + app/src/main/res/values/strings.xml | 8 + 20 files changed, 404 insertions(+), 7 deletions(-) create mode 100644 .idea/.name create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/kotlinc.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/src/main/java/com/example/bcsd_android_2025_1/ListData.kt create mode 100644 app/src/main/java/com/example/bcsd_android_2025_1/RecyclerViewAdapter.kt create mode 100644 app/src/main/res/drawable/album_image_default_aespa.png create mode 100644 app/src/main/res/layout/item_recyclerview.xml 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..02a7102 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + + \ 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/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /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..3ec5dfe 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -36,7 +36,6 @@ android { } dependencies { - 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..4ceebf6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + + when(isGranted) { + true->{ + recyclerView.visibility = View.VISIBLE + permissionButton.visibility = View.GONE + permissionTextView.visibility = View.GONE + loadMusics() + } + else->{ + when(shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) + { + true->permissionDialog(true) + else->{ + permissionDialog(false) + } + } + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + + recyclerView = findViewById(R.id.recycler_view) + permissionTextView = findViewById(R.id.need_permission_textview) + permissionButton = findViewById(R.id.need_permission_button) + + if(permissionGranted()){ + recyclerView.visibility = View.VISIBLE + permissionButton.visibility = View.GONE + permissionTextView.visibility = View.GONE + loadMusics() + }else{ + recyclerView.visibility = View.GONE + permissionButton.visibility = View.VISIBLE + permissionTextView.visibility = View.VISIBLE + requestPermissionLaunch() + } + + permissionButton.setOnClickListener{ + val intent = Intent() + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", packageName, null) + intent.setData(uri) + startActivity(intent) + } + } + + override fun onResume() { + super.onResume() + if(permissionGranted()){ + recyclerView.visibility = View.VISIBLE + permissionButton.visibility = View.GONE + permissionTextView.visibility = View.GONE + loadMusics() + }else{ + recyclerView.visibility = View.GONE + permissionButton.visibility = View.VISIBLE + permissionTextView.visibility = View.VISIBLE + } + } + + private fun permissionGranted():Boolean{ + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){ + Manifest.permission.READ_MEDIA_AUDIO + }else{ + Manifest.permission.READ_EXTERNAL_STORAGE + } + return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED } -} \ No newline at end of file + + private fun requestPermissionLaunch(){ + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){ + Manifest.permission.READ_MEDIA_AUDIO + }else{ + Manifest.permission.READ_EXTERNAL_STORAGE + } + requestPermission.launch(permission) + } + + private fun permissionDialog(requestDialog : Boolean){ + val builder = androidx.appcompat.app.AlertDialog.Builder(this) + builder.setTitle(R.string.permission_title_dialog) + builder.setMessage(R.string.permission_message_dialog) + builder.setPositiveButton(R.string.ok){dialog, _-> + dialog.dismiss() + if(!requestDialog){ + val intent = Intent() + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", packageName, null) + intent.setData(uri) + startActivity(intent) + } + } + builder.setNegativeButton(R.string.no){dialog, _-> + dialog.dismiss() + } + builder.show() + } + + + private fun loadMusics(){ + val list = ArrayList() + + val projection = arrayOf( + MediaStore.Audio.Media.TITLE, + MediaStore.Audio.Media.ARTIST, + MediaStore.Audio.Media.DURATION, + MediaStore.Audio.Media._ID, + MediaStore.Audio.Media.ALBUM_ID) + + contentResolver.query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + projection, + null, + null, + null + )?.use{ cursor-> + val idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID) + val titleIndex = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE) + val nameIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST) + val timeIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION) + val albumIdIndex = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID) + while (cursor.moveToNext()){ + val id = cursor.getLong(idIndex) + val title = cursor.getString(titleIndex)?:R.string.default_name.toString() + val name = cursor.getString(nameIndex)?:R.string.default_name.toString() + val time = cursor.getLong(timeIndex) + val albumId = cursor.getLong(albumIdIndex) + val musicUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id) + + list.add(ListData(musicUri, albumId, title, name, time)) + } + } + recyclerView.adapter = RecyclerViewAdapter(list) + } +} + diff --git a/app/src/main/java/com/example/bcsd_android_2025_1/RecyclerViewAdapter.kt b/app/src/main/java/com/example/bcsd_android_2025_1/RecyclerViewAdapter.kt new file mode 100644 index 0000000..ea5bc4e --- /dev/null +++ b/app/src/main/java/com/example/bcsd_android_2025_1/RecyclerViewAdapter.kt @@ -0,0 +1,65 @@ +package com.example.bcsd_android_2025_1 + +import android.graphics.BitmapFactory +import android.media.MediaMetadataRetriever +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView + +class RecyclerViewAdapter(private val items:ArrayList): RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false) + return ViewHolder(inflatedView) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val item = items[position] + holder.bind(item, position) + } + + override fun getItemCount(): Int = items.size + + inner class ViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { + fun bind(item: ListData, position: Int) { + val imageItem: ImageView = view.findViewById(R.id.imageview_item) + val titleItem: TextView = view.findViewById(R.id.title_textview_item) + val nameItem: TextView = view.findViewById(R.id.name_textview_item) + val timeItem: TextView = view.findViewById(R.id.time_textview_item) + titleItem.text = item.title + nameItem.text = item.name + timeItem.text = timeSet(item.time) + + val retriever = MediaMetadataRetriever() + + try { + retriever.setDataSource(view.context, item.musicUri) + + val art = retriever.embeddedPicture + if (art != null) { + val bitmap = BitmapFactory.decodeByteArray(art, 0, art.size) + imageItem.setImageBitmap(bitmap) + } else { + imageItem.setImageResource(R.drawable.album_image_default_aespa) + } + retriever.release() + } catch (e: Exception) { + e.printStackTrace() + imageItem.setImageResource(R.drawable.album_image_default_aespa) + } + } + } + + private fun timeSet(time:Long):String{ + val hour = time/(1000*60*60) + val min = time/(1000*60)%60 + val sec = time/1000%60 + return if(hour>0){ + "%d:%02d:%02d".format(hour, min, sec) + }else{ + "%02d:%02d".format(min,sec) + } + } +} diff --git a/app/src/main/res/drawable/album_image_default_aespa.png b/app/src/main/res/drawable/album_image_default_aespa.png new file mode 100644 index 0000000000000000000000000000000000000000..4eaeb476df8c16da50d0446ab51b0e9c82e980a5 GIT binary patch literal 12244 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 + + + +