본문 바로가기
Projects/It's My Waye

[It's My Waye] 10. 알람 기능 구현 - 알람 켜기

by DevJaewoo 2022. 4. 27.
반응형

개발을 미루고 미루다가 어느덧 마지막 글을 올린 날에서 3달 가량이 지나버렸다.

꾸준히 개발해왔으면 지금쯤 거의 다 완성돼있었을텐데 그렇게 하지 않고 게으름 피운 나에게 화가 난다.

이제 와서 다시 해봐야 늦었다는 생각도 늘지만 지금부터라도 다시 시작해보려 한다.


구현할 기능

기능 구현에 앞서 시나리오는 다음과 같다.

  1. 다른 앱 (Ex. 디스코드, 카카오톡) 에서 내가 알람을 켜둔 아이템의 이름이 메시지에 포함된 Notification 감지
  2. 해당 아이템의 알람 세부설정 확인 (Ex. 알림음, 볼륨, 반복 횟수, 반복 간격)
  3. 세부설정에 따라 알람 재생

이 중에서 3번의 역할을 하는 클래스를 구현했다.


알람 서비스 구현

알람 서비스는 알람을 재생/정지하고, 알람을 재생할 때 현재 음소거 모드와 볼륨을 변경하는 역할을 한다.

UI가 표시되고 있는지와 상관없이 동작해야 하기 때문에 Activity가 아닌 Service로 만들었다.

 

우선 서비스에 보낼 Intent 관련 상수를 정의했다.

 

// Alarm
const val ACTION_ALARM_ON: String = "com.devjaewoo.itsmywaye.extra.ACTION_ALARM_ON"
const val ACTION_ALARM_OFF: String = "com.devjaewoo.itsmywaye.extra.ACTION_ALARM_OFF"

const val EXTRA_ALARM_URI: String = "com.devjaewoo.itsmywaye.extra.EXTRA_ALARM_URI"
const val EXTRA_ALARM_VOLUME: String = "com.devjaewoo.itsmywaye.extra.EXTRA_ALARM_VOLUME"
const val EXTRA_ALARM_REPEAT: String = "com.devjaewoo.itsmywaye.extra.EXTRA_ALARM_REPEAT"
const val EXTRA_ALARM_INTERVAL: String = "com.devjaewoo.itsmywaye.extra.EXTRA_ALARM_INTERVAL"

 

이제 onStartCommand에서 action을 통해 알람을 켜야 하는지, 꺼야 하는지 알 수 있다.

아래와 같이 Intent에서 알람 정보를 받아와 처리해주면 된다.

 

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

        if(intent != null) {
            if(intent.action == ACTION_ALARM_ON) {
                uri = intent.getStringExtra(EXTRA_ALARM_URI) ?: ""
                volume = intent.getIntExtra(EXTRA_ALARM_VOLUME, 100)
                repeatTimes = intent.getIntExtra(EXTRA_ALARM_REPEAT, 3)
                interval = intent.getIntExtra(EXTRA_ALARM_INTERVAL, 5)
                
                playRingtone()
            }
            else {
                stopRingtone()
            }
        }

        return super.onStartCommand(intent, flags, startId)
    }

 

그 다음 실제 알람을 켜고 끄는 코드를 작성했다.

처음엔 Ringtone 클래스를 사용하려 했으나, 원하는 기능 중 하나가 잘 동작하지 않아 MediaPlayer 클래스로 바꿨다.

MediaPlayer를 통한 소리 제어 방법은 다음에 따로 올려야겠다.

 

Ringtone은 이전에 올려둔게 있다.

 

[Android] Ringtone 재생 및 목록 가져오기

Ringtone 재생 val ringtoneUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM) val ringtone: Ringtone = RingtoneManager.getRingtone(context, ringtoneUri) ringtone.play() ringtoneUri..

devjaewoo.tistory.com

 

if (mediaPlayer == null || !(mediaPlayer!!.isPlaying)) {
    if(RingtoneManager.getRingtone(applicationContext, Uri.parse(uri)) == null) {
        Log.w(TAG, "onStartCommand: Cannot find ringtone at $uri. Setting uri to default alarm ringtone.")
        uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString()
    }

    mediaPlayer = MediaPlayer.create(this, Uri.parse(uri)).apply {
        stop()
        isLooping = true
        setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()) //알람 볼륨으로 소리 켬
        prepare()
    }

    playRingtone()
}

 

코드를 간단히 설명하자면 현재 알람을 켤 수 있는 상태일 경우 알람 스트림으로 지정된 uri의 알림음을 틀어주는 코드이다.

 

안드로이드에는 소리를 내보낼 수 있는 스트림이 여러개 있는데, 그중 하나가 알람 스트림이다.

전화벨 소리는 벨소리 볼륨, 게임이나 유튜브는 미디어, 통화는 통화 볼륨 스트림으로 출력된다.

 

아까 Ringtone으로 하려다가 안됐다고 했던게 바로 이거였다.

 

볼륨 조절 창
기종마다 UI가 조금씩 다를 수 있다.

 

알람이 나오는 것은 확인했지만, 볼륨이 너무 작았다.

웨이가 떠서 알람이 정상적으로 울렸는데 하필 내가 음소거 모드로 설정해둬서 알람음을 못들어 웨이를 못먹으면 그만큼 억울한것도 없을것이다.

 

이런 불상사를 방지하기 위해 알람이 울릴 때 음소거를 해제하고, 알람 볼륨을 설정한 값으로 높여주고, 알람을 끌 때 다시 이전 값으로 되돌아가도록 코드를 작성했다.

 

lateinit var audioManager: AudioManager
private var savedVolume: Int = 0
private var savedRingerMode: Int = 0

override fun onCreate() {
    super.onCreate()
    audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
}
    
private fun changeAudioState(volume: Int) {

    savedRingerMode = audioManager.ringerMode
    savedVolume = audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION)

    Log.d(TAG, "changeAudioState: " +
            "SavedVolume: $savedVolume " +
            "MaxVolume: ${audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION)} " +
            "CurrentVolume: ${(audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION) * (volume / 100.0)).toInt()}")

    audioManager.ringerMode = AudioManager.RINGER_MODE_NORMAL
    audioManager.setStreamVolume(
        AudioManager.STREAM_NOTIFICATION,
        (audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION) * (volume / 100.0)).toInt(),
        0)
}

private fun restoreAudioState() {
    audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, savedVolume, 0)
    audioManager.ringerMode = savedRingerMode
}

 

이제 작성한 아래의 함수들을 통해 아래의 시나리오에 맞게 핸드폰을 제어할 수 있다.

 

  1. 음소거 해제, 볼륨 변경
  2. 알람 켜기
  3. 알람 끄기
  4. 음소거, 볼륨 원상복구

 

작동영상은 따로 올리지 않겠다.

반응형