숙면 타이머!(안드로이드 토이프로젝트,Kotlin) - Notification

Jamwon·2021년 8월 26일
1

음악멈춰!

목록 보기
1/1

유튜브 뮤직을 사용하던 와중...유튜브 뮤직에는 몇분뒤 음악을 꺼주는 기능이없다는 것을 깨닫고 불편해 해서 안드로이드 공부도 하고있는데 내가 만들어보자! 해서 playstore에 처음으로 올리는(연습용) 앱을 만들어 보고있다.

플레이스토어 주소

현재는 진짜 말그대로 얼마만큼의 시간후에 음악을 멈춰주는 기능만 넣어놨다 궁금해서 광고도 넣어봤다ㅎㅎ

주변 지인들의 사용기를 듣고 기능을 하나씩 추가할려고 한다!

오늘 추가해볼건 상단에 몇분뒤 정지되는지 알려주는 상단바 알람과 알림 아이콘을 만들어본다!

알림 개요

공식문서 링크
(영어로 읽는걸 습관화 하자..! 뒤에 ?hl=ko를 지우면 영어문서다)

읽어보면 Status bar와 notification drawer 가 있다.

Status bar and notification drawer

Status bar에는 상태바에 icon의 형태로 나타난다.

상태바를 내려서 notification drawer를 열 수 있는데 상세정보와 알람에 대한 action을 취할 수 있다.

Heads-up notification

안드로이드 5.0부터 알림은 heads-up notification이라는 떠다니는 화면에 나타날 수 있다!

이 행위는 중요한 알림이거나 즉시 사용자에게 알릴때 나타나며 기기가 잠금해제되어있을때 나타난다고 한다.
(이번 프로젝트에서는 사용하지 않는다)

Lock screen

안드로이드 5.0부터 잠금화면에 알람이 나타날 수 있다고 한다.

유저는 시스템 설정으로 잠금화면에 알림의 단계(level of detail)을 정할 수 있고 끌수도 있다.

안드로이드 8.0부터는 각각의 잠금화면 알람을 notification channel를 이용해서 끄거나 킬 수 있다고 한다.

App icon badge

안드로이드 8.0(API level 26) 부터 지원한다고 한다.
어플의 icon이 새로운 알람을 색이있는 badge(notification dot이라고도 불린다)로 알람을 보여준다.

사용자는 앱 아이콘을 길게 누름으로써 어플의 알람을 볼수있다.

이 기능은 개인적으로 어플사용하면서 잘 안쓰는것 같다. 어플을 홈화면에 추가, 삭제, 이런것들도 이 기능으로 연결하는 것 같다.

Wear Os devices

웨어러블 기기에서의 알람..! 우선 pass!

알람 구성요소


1. 작은 아이콘 : 'setSamllIcon()'을 사용해서 만든다.
2. 앱 이름: system에서 제공
3. Time stamp : system에서 제공하지만 'setWhen()' 을 이용해서 override 할 수 있다고 한다.

'setShowWhen(false)' 를 이용해서 숨길 수 있다.
4. 큰 아이콘 : 부가옵션. 보통 연락처의 사진용으로 쓰인다고 한다. 앱 icon으로 사용하지 말라고 한다.
'setLargeIcon()' 으로 생성

  1. 제목 : 부가옵션 'setContentTitle()로 생성
  2. 글 : 부가옵션 'setContentText()로 생성

공식문서에서 강력하게 시스템 템플릿을 사용하는것을 권장한다고 한다(모든 기기에 호환되게)

하지만 custom notification layout을 만들 수있다고 한다.

알림 만들기

어플의 시작 버튼을 누르면 알림이 상단바에 생기게 만들어야겠다!

근데 알림창에도 ~분 남았습니다를 보여주고 싶었기 때문에 progress bar을 사용했다!

알림은 앱에서 사용한 CountDownTimer에 1초가 지날때 마다 갱신되는 식으로 만들어주었다.

지금 CountDownTimer에는 initialMillis(총 시간)을 받아주고 1초마다 onTick이 작동한다.

showNotification

알림을 보여주는 함수로 인자를 총시간과 현재 시간을 받아주었다. 원래는 Thread로 1초마다 따로 했었는데 생각해보니깐 그냥 알람을 만들어주는 함수를 countDownTimer의 onTick 마다 보여주면 되서 바꿔주었다.

private fun showNotification(startMillis: Long, initialMillis: Long) {
        val startMillisSeconds = (startMillis / 1000).toInt()
        val notiRemainSeconds = (initialMillis / 1000).toInt()
        val remainSeconds = "%02d초".format(notiRemainSeconds % 60)
        var remainHours = "%02d시간".format(notiRemainSeconds / 3600)
        var remainMinutes = "%02d분".format((notiRemainSeconds / 60) % 60)
        if (notiRemainSeconds / 3600 == 0) {
            remainHours = ""
        }
        if ((notiRemainSeconds / 60) % 60 == 0) {
            remainMinutes = ""
        }

        val intent = Intent(this, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
        }


        val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

        createNotificationChannel("stop")
        val builder = NotificationCompat.Builder(this, "stop").apply {
            setSmallIcon(R.drawable.ic_launcher_background)
            setContentTitle("미디어 종료 시각")
            setContentText("oh..")
            setContentIntent(pendingIntent)
            
            priority = NotificationCompat.PRIORITY_LOW
        }
        val handler = Handler()

        with(NotificationManagerCompat.from(this)) {

            builder.setProgress(startMillisSeconds, (startMillisSeconds - notiRemainSeconds), false)
            notify(notificationId, builder.build())

            Thread(Runnable {


                handler.post(Runnable {
                    if (notiRemainSeconds == 0) {
                        builder.setContentText("종료되었습니다.")
                        builder.setProgress(0, 0, false)
                    } else {

                        builder.setContentText("$remainHours $remainMinutes $remainSeconds 후에 종료")
                        builder.setProgress(
                            startMillisSeconds,
                            (startMillisSeconds - notiRemainSeconds),
                            false
                        )

                    }
                    notify(notificationId, builder.build())

                })

            }).start()
        }

    }

우선 코드를 보면 Long으로된 시간을 받아서 총시간과 남은 시간을 Int로 변환해주었다. 그리고 String 형식으로 시간 분 초 형식으로 변환해주었다.

if문으로 시간과 분이 0이면 공백으로 표시해서 알림창에 나타나지 않게 처리해주었다. (뭔가 더 좋은 방법이 있을거 같은데... 현재로선 모르겠다 ㅠㅠ)

알람 만들기

만드는 법은 공식문서 참조!!!

알람 채널과 콘텐츠를 설정해줘야한다.

알람 누를시 어플로 복귀

알람에서 activity 실행하기 공식문서

알람 자체를 눌렀을때 다시 앱으로 돌아가는 기능을 위해서 intent를 만들어주었고

flag를 맨위에 있는 FLAG_ACTIVITY_SINGLE_TOP을 이용해서 만들어주었다.

val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

위와같은 pendingIntent를 만들어서 builder에서 setContentIntent로 전달해주면 된다.

progressbar 만들기

진행 표시줄 공식문서

Thread에서 위에서 만든 남은시간이 0일때 progressbar값을 0으로 만들고 "종료되었습니다." 라는 text를 표시한다.

그외에는 위에서 정의한 남은 시간 분 초 를 text로 표시하고

setProgrss(max값, 현재값, false)

를 호출해서 progress bar 진행사항을 보여준다.

알람 끄기

음악 멈춰!를 중지하면 알람이 없어지게 해야한다!
이땐

        NotificationManagerCompat.from(this).apply {
            cancelAll()
        }

를 이용하면 알람을 종료할 수 있다.

그리고 어플을 종료할때에도 알람창은 계속 띄워있기 때문에 onDestory일때도 cancelAll()을 해주었다.

전체 코드는...올리진 않겠다!
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

결과물

위처럼 알림을 누르면 앱으로 돌아가고 중지하면 알림창이 없어진다. !!!

원래는 알림창에 버튼을 만들어서 countdownTimer의 일시정지 다시 시작을 만들어보고 싶었지만 다음에...!

알람 notification을 LOW로 바꿔야한다
NotificationManager.IMPORTANCE_LOW
로 바꾸지 안으면 매초 알람이 울려댄다... 매번 폰을 무음모드로 실행해봐서 몰랐던 사실...

어플을 최근 앱 리스트에서 모두 종류하면(onDestory) 알림을 삭제하는 function을 썻었는데 최근 앱리스트에서 swipe up해서 삭제하면 앱은 작동을 안하는데 알람은 남아있어서 찾아보았는데 onStop에서도 알림을 삭제하는 function을 썻더니 다시 삭제되었다

profile
한걸음씩 위로 자유롭게

0개의 댓글