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

[It's My Waye] 11. 알람 기능 구현 - 알람 제어

by DevJaewoo 2022. 4. 27.
반응형

Intro

이전엔 단순히 알람을 켜고 끄기만 하는 서비스를 작성했다.

이제 알람을 언제 켜고, 언제 끌지 결정하는 클래스를 만들어야 한다.

 

모든 알람은 이 클래스를 통해 제어할 예정이기 때문에 싱글톤 패턴으로 만들어야 한다.

Kotlin에선 싱글톤 패턴을 대체할 수 있는 object라는 키워드를 제공한다.

class 대신 object로 선언하면 static으로 사용하는것과 비슷한 효과를 낸다.


알람 켜기

다른 앱의 noti를 읽고, 그 noti의 메시지에 내가 알람을 켜둔 아이템이 포함되어 있으면 알람을 켜는것이 기본 시나리오이다.

 

noti 내용은 결국 String으로 전달되기 때문에, String을 받아 알림을 켜주는 함수를 만들면 된다.

우선 String 안의 아이템이 있는지 확인해 index를 반환하는 함수를 만들었다.

 

private fun getItemIndex(message: String): Int {
    val formattedMessage = message.blankRemovedString
    val itemList = ApplicationManager.ItemList

    for(i in itemList.indices) {
        if(formattedMessage.contains(itemList[i].name.blankRemovedString)) {
            Log.d(TAG, "getAlarmIndex: Message $message contains item ${itemList[i].name}")
            return i
        }
    }

    return -1
}

 

그 다음 index를 통해 Item 정보를 받아 AlarmService에 ON 신호를 보내는 함수를 만들었다.

 

fun startAlarm(message: String) {

    val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
    if(!isAlarmEnabled(currentHour)) {
        Log.d(TAG, "startAlarm: Alarm is disabled at $currentHour.")
        return
    }

    val itemIndex = getItemIndex(message)
    Log.d(TAG, "startAlarm: Item index of $message is $itemIndex")
    if(itemIndex == -1) return

    val item = ApplicationManager.ItemList[itemIndex]
    Log.d(TAG, "startAlarm: Alarm Enabled: ${item.enabled}")
    if(!item.enabled) return

    val alarm = item.alarm ?: Alarm(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString(), 100, 3, 5)

    val alarmIntent = Intent(ApplicationManager.applicationContext, AlarmService::class.java).apply {
        action = ACTION_ALARM_ON
        putExtra(EXTRA_ALARM_URI, alarm.filePath)
        putExtra(EXTRA_ALARM_VOLUME, alarm.volume)
        putExtra(EXTRA_ALARM_REPEAT, alarm.repeatTimes)
        putExtra(EXTRA_ALARM_INTERVAL, alarm.interval)
    }

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        ApplicationManager.applicationContext.startService(alarmIntent)
    }
    else {
        ApplicationManager.applicationContext.startService(alarmIntent)
    }
}

 

이제 외부에서 Alarm.startAlarm("웨이") 이렇게 Item 이름을 담아 호출하면 알람이 켜진다.


알람 끄기

알람이 울리기 시작하면 noti를 띄우고, 그 noti에 알람 끄기 버튼을 만들어 끄게 할 예정이다.

나중에는 실제 알람처럼 전체화면으로 띄우는 기능도 추가할까 고민중이긴 한데, 그건 나중에 생각하도록 하자.

 

아래의 사이트를 참고해 만들었다.

https://developer.android.com/training/notify-user/build-notification?hl=ko 

 

알림 만들기  |  Android 개발자  |  Android Developers

알림 만들기 알림은 사용 중이 아닌 앱의 이벤트에 관한 짧고 시기적절한 정보를 제공합니다. 이 페이지에서는 Android 4.0(API 레벨 14) 이상의 다양한 기능을 사용하여 알림을 만드는 방법을 설명

developer.android.com

 

fun startAlarm(message: String) {
    ...
    createNotification(item.name)
}

private fun createNotification(content: String) {
    val intent = Intent(ApplicationManager.applicationContext, AlarmService::class.java).apply {
        action = ACTION_ALARM_OFF
        putExtra(EXTRA_NOTIFICATION_ID, NOTIFICATION_DEFAULT_ID)
    }

    val pendingIntent: PendingIntent = PendingIntent.getService(
        ApplicationManager.applicationContext,
        0,
        intent,
        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_CANCEL_CURRENT)

    val notificationManager = ApplicationManager.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val notification = NotificationCompat.Builder(ApplicationManager.applicationContext, NOTIFICATION_DEFAULT_CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_baseline_access_alarm_24)
        .setContentTitle("마이웨이")
        .setContentText(content)
        .addAction(R.drawable.ic_baseline_access_alarm_24, "알람 끄기", pendingIntent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setOngoing(true)
        .build()

    Log.d(TAG, "createNotification: $APPLICATION_NAME/$content")
    notificationManager.notify(NOTIFICATION_DEFAULT_ID, notification)
}

 

이제 알람이 울리기 시작함과 동시에 Noti가 생기고, 그 noti의 알람 끄기 버튼을 누르면 알람이 꺼진다.

 

반응형