-
Notifications
You must be signed in to change notification settings - Fork 0
과제9 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: assignment_08
Are you sure you want to change the base?
과제9 #6
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,57 +1,83 @@ | ||
| package com.example.assignment02 | ||
|
|
||
| import android.Manifest | ||
| import android.annotation.SuppressLint | ||
| import android.content.ContentResolver | ||
| import android.content.Context | ||
| import android.content.Intent | ||
| import android.content.pm.PackageManager | ||
| import android.net.Uri | ||
| import android.content.res.ColorStateList | ||
| import android.graphics.Color | ||
| import android.os.BatteryManager | ||
| import android.os.Bundle | ||
| import android.provider.MediaStore | ||
| import android.util.Log | ||
| import android.view.LayoutInflater | ||
| import android.view.View | ||
| import android.view.ViewGroup | ||
| import android.widget.LinearLayout | ||
| import android.widget.TextView | ||
| import androidx.core.content.ContextCompat | ||
| import androidx.core.graphics.ColorUtils | ||
| import androidx.fragment.app.Fragment | ||
| import androidx.recyclerview.widget.LinearLayoutManager | ||
| import androidx.recyclerview.widget.RecyclerView | ||
| import java.io.File | ||
|
|
||
| class ListFragment : Fragment() { | ||
|
|
||
| private val data = mutableListOf<Item>() | ||
| private lateinit var adapter: Adapter | ||
| private lateinit var name: TextView | ||
| private lateinit var time: TextView | ||
| private lateinit var energy: LinearLayout | ||
|
|
||
| companion object { | ||
| fun newInstance(): ListFragment { | ||
| return ListFragment() | ||
| } | ||
| } | ||
|
|
||
| @SuppressLint("MissingInflatedId") | ||
| override fun onCreateView( | ||
| inflater: LayoutInflater, container: ViewGroup?, | ||
| savedInstanceState: Bundle? | ||
| ): View? { | ||
| val view = inflater.inflate(R.layout.fragment_list, container, false) | ||
|
|
||
| name = view.findViewById(R.id.name) | ||
| time = view.findViewById(R.id.time) | ||
| energy = view.findViewById(R.id.energe) | ||
|
|
||
| // 배터리에 따라 배경색 변경하기! | ||
| val battery = getBatteryData(requireContext()) // 0~100(%) | ||
| energy.backgroundTintList = ColorStateList.valueOf(ColorUtils.blendARGB(Color.parseColor("#00B0FF"), Color.parseColor("#FFFFFF"), battery / 100f)) | ||
|
|
||
| val recycler_list: RecyclerView = view.findViewById(R.id.recycler_list) | ||
| recycler_list.layoutManager = LinearLayoutManager(requireContext()) | ||
| adapter = Adapter(data) | ||
| adapter = Adapter(data, name, time) | ||
| recycler_list.adapter = adapter | ||
|
|
||
| if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED | ||
| if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED | ||
| ) { | ||
| // 권한이 있음 -> 음악 파일 추가 | ||
| getMusicFilesData() | ||
| } else { | ||
| // 권한이 없음 | ||
| openFragment() | ||
| } | ||
| else if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.FOREGROUND_SERVICE) != PackageManager.PERMISSION_GRANTED | ||
| ) { | ||
| openFragment() | ||
| } | ||
| else { | ||
| // 권한이 있음 | ||
| getMusicFilesData() | ||
| } | ||
|
|
||
| return view | ||
| } | ||
|
|
||
| fun getBatteryData(context: Context): Int { | ||
| val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager | ||
| return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) | ||
| } | ||
|
|
||
| fun getMusicFilesData() { | ||
| val contentResolver: ContentResolver = requireContext().contentResolver | ||
| val uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI | ||
|
|
@@ -71,9 +97,7 @@ class ListFragment : Fragment() { | |
| val dataIndex = it.getColumnIndex(MediaStore.Audio.Media.DATA) | ||
|
|
||
| while (it.moveToNext()) { | ||
| Log.d("File Path", "음악 파일 경로: ${it.getString(dataIndex)}") | ||
|
|
||
| val item = Item(it.getString(titleIndex) ?: "Unknown Title", it.getString(artistIndex) ?: "Unknown Artist", it.getLong(durationIndex) ?: 0) | ||
| val item = Item(it.getString(titleIndex) ?: "Unknown Title", it.getString(artistIndex) ?: "Unknown Artist", it.getLong(durationIndex) ?: 0, it.getString(dataIndex) ?: "") | ||
| data.add(item) | ||
| } | ||
| adapter.notifyDataSetChanged() | ||
|
|
@@ -91,7 +115,7 @@ class ListFragment : Fragment() { | |
| .commit() | ||
| } | ||
|
|
||
| class Adapter(private val data: MutableList<Item>) : RecyclerView.Adapter<Adapter.ViewHolder>() { | ||
| class Adapter(private val data: MutableList<Item>, private var name_view:TextView, private var time_view:TextView) : RecyclerView.Adapter<Adapter.ViewHolder>() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. recyclerview의 아이템 변동 사항이 없다면 MutableList 보단 불변 List를 사용하는 게 좋습니다! |
||
|
|
||
| class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
| val title: TextView = itemView.findViewById(R.id.title) | ||
|
|
@@ -111,11 +135,19 @@ class ListFragment : Fragment() { | |
| val m = (item.duration/60000).toString() | ||
| val s = (item.duration/1000 %60).toString() | ||
| holder.duration.text = "$m:$s" | ||
|
|
||
| holder.itemView.setOnClickListener { | ||
| name_view.text = item.title | ||
| time_view.text = holder.duration.text | ||
| val intent = Intent(holder.itemView.context, PlayMusic::class.java).apply { | ||
| putExtra("uri", item.uri) | ||
| } | ||
| ContextCompat.startForegroundService(holder.itemView.context, intent) | ||
| } | ||
| } | ||
|
|
||
| override fun getItemCount(): Int = data.size | ||
| } | ||
|
|
||
| data class Item(val title: String, val artist: String, val duration: Long) | ||
|
|
||
| data class Item(val title: String, val artist: String, val duration: Long, val uri: String) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| package com.example.assignment02 | ||
|
|
||
| import android.app.Notification | ||
| 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.os.Build | ||
| import android.os.IBinder | ||
| import androidx.core.app.NotificationCompat | ||
| import android.net.Uri | ||
| import android.util.Log | ||
|
|
||
| class PlayMusic : Service() { | ||
|
|
||
| private var mediaPlayer: MediaPlayer? = null | ||
| private val channel1 = "channel1" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. companion object로 선언해주는 게 좋아보입니당 |
||
|
|
||
| override fun onCreate() { | ||
| super.onCreate() | ||
|
|
||
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
| val channel = NotificationChannel( | ||
| channel1, | ||
| "music", | ||
| NotificationManager.IMPORTANCE_LOW | ||
| ) | ||
| val notificationManager = getSystemService(NotificationManager::class.java) | ||
| notificationManager.createNotificationChannel(channel) | ||
| } | ||
|
|
||
| val intent = Intent(this, MainActivity::class.java) | ||
| val pending_intent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE) | ||
|
|
||
| // 알림 생성 | ||
| val notification: Notification = NotificationCompat.Builder(this, channel1) | ||
| .setContentTitle("음악 재생 중...") | ||
| .setContentText("백그라운드에서 음악이 재생되고 있습니다.") | ||
| .setSmallIcon(androidx.core.R.drawable.ic_call_answer) | ||
| .setContentIntent(pending_intent) | ||
| .setAutoCancel(true) | ||
| .build() | ||
|
|
||
| startForeground(1, notification) | ||
| } | ||
|
|
||
| override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { | ||
| val uri_string = intent.getStringExtra("uri") | ||
| Log.d("PlayMusic", "URI: $uri_string") | ||
| uri_string?.let { | ||
| val uri = Uri.parse(it) | ||
| musicPlay(uri) | ||
| } | ||
| return START_STICKY | ||
| } | ||
|
|
||
| private fun musicPlay(uri: Uri) { | ||
| mediaPlayer = MediaPlayer().apply { | ||
| setDataSource(applicationContext, uri) | ||
| setOnPreparedListener { | ||
| it.start() | ||
| } | ||
| prepareAsync() | ||
| } | ||
| } | ||
|
|
||
| override fun onBind(intent: Intent?): IBinder? { | ||
| return null | ||
| } | ||
|
|
||
| override fun onDestroy() { | ||
| super.onDestroy() | ||
| mediaPlayer?.release() | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리사이클러뷰는 snake_case로 선언하시고 여기서는 camelCase를 사용하셨는데, 이렇게 통일하지 않고 사용하시면 코드의 가독성이 떨어질 수 있어요. 웬만해서는 네이밍 컨벤션 통일해주세요!