본문 바로가기

Android/정리 노트

[Android/안드로이드] VibrationEffect 사용하기(createWaveForm amplitude 제대로 사용하기)

LG/v30/os8.0.0

언젠가부터 위처럼 os설정에 진동 세기조절이 있어 이를 컨트롤 할 수 있는 라이브러리를 찾게되었다.

찾아보니 API26부터 지원되는 VibrationEffect라는 클래스가 존재했다.

이 포스팅은 VibrationEffect를 다루고 createWaveform 메소드를 어떻게 사용해야 하는지에 대한 정리이다.

Vibrator.vibrate()


Vibrator.vibrate()

기존의 milliseconds와 pattern을 사용하는 메소드는 deprecated되고 VibrationEffect를 인자로 받는 메소드가 있다.

여기서는 AudioAttribute를 사용하는 메소드는 다루지 않는다.

VibrationEffect


VibrationEffect

두가지 메소드가 있다.

createOneShot(milliseconds, amplitude)

createWaveForm(timings: LongArray, amplitudes: IntArray, repeat)

createOneShot은 milliseconds의 시간동안 amplitude의 세기만큼 진동하라

createWaveForm은 timings와 amplitudes의 쌍으로 wave의 형태를 만들어 진동을 발생시킨다.

createOneShot


        vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

        button.setOnClickListener {
            vibrator.vibrate(VibrationEffect.createOneShot(1000, 50))
            vibrator.vibrate(VibrationEffect.)
        }

        button2.setOnClickListener {
            vibrator.vibrate(VibrationEffect.createOneShot(1000, 70))
            vibrator.vibrate(VibrationEffect.)
        }

위처럼 1초동안 50, 70의 강도(amplitude)로 단발성 진동을 발생시킨다.

amplitude


amplitude 값은 0~255의 사이 값을 가지고 있다.

VibrationEffect.DEFAULT_AMPLITUDE(== -1) 을 주게되면 시스템 기본 진동 세기를 적용시킨다.

createWaveForm(API LEVEL 28)


위와 같은 진동 세기 패턴을 만든다고 가정해보자

Waveform이라고 해서 자연스러운 곡선이 될 줄 알았는데 저런 식으로 밖에 안되는 것 같다.

패턴을 만드는 규칙은 다음과 같다.

"얼마만큼의 시간동안 얼마만큼의 세기를 발생시킨다" 를 기준으로 시간세기의 Array를 만든다.

위 그래프대로 코드를 만들면

        setContentView(R.layout.activity_main)

        vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

        val timings = longArrayOf(100, 100, 400, 200, 400)
        val amplitudes = intArrayOf(0, 50, 100, 50, 150)

        button.setOnClickListener {
            vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
        }
        //os가 pie 미만이라면 정상적으로 동작하지 않는다. 이에 대한 경우는 포스팅 하단의 내용을 참고

코드를 보면 알 수 있듯이 두 배열의 size는 같아야 한다.

그리고 각 배열의 처음 값은 첫 진동이 시작하기까지 걸리는 시간을 의미한다.

위 그래프에 의하면 진동은 100ms 후에 50의 세기로 시작한다.

만약, 진동을 바로 시작하고 싶다면 두 배열의 시작 값을 둘다 0으로 주면 된다.

무조건 첫번째 값을 진동이 없는 시간으로 인식하니 주의

만약 amplitudes의 첫 값에 0이 아닌 값을 입력시 ignore된다.(의미없는 값)

repeat을 -1로 주면 반복을 하지 않는 것을 의미한다. //TODO : repeat값에 따른 변화

amplitude가 없는 createWaveform(timings, repeat)의 경우는 기존의 pattern사용처럼 on-off타이밍을 지정하여 진동을 주게 된다.

API LEVEL 26-27의 경우


테스트 기기가 적어 27도 포함일지는 모르겠지만 일단 이 경우에 포함시켰다.

26-27의 경우 위처럼 코드를 작성해도 amplitudes의 첫 값 세기로 timing의 길이 합만큼 진동을 하게 된다.(위 코드 기준 50amp에 1100ms로 진동)

os에서 처리를 못하는건지 모르겠는데 진동 세기의 변화가 드러나지 않아 정상 작동을 하지 않는다.

이를 해결하기 위해서는 사이에 0을 끼워넣으면 된다.

        setContentView(R.layout.activity_main)

        vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

        val timings = longArrayOf(100, 100, 0, 400, 0, 200, 0, 400)
        val amplitudes = intArrayOf(0, 50, 0, 100, 0, 50, 0, 150)

        button.setOnClickListener {
            vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
        }

중간중간 끊어주면 pattern내에서 세기의 변화가 일어나긴 한다. 다만 26-27에서는 바로 다른 세기를 발생시키는 게 안되는 것 같아 위처럼 그래프 상으로 전혀 변화는 없지만 중간에 0을 끼워 넣는 꼼수를 부렸더니 28에서와 같이 동작한다.

결론

버전분기를 26미만, 26-27, 28로 하던지

26미만과 26~으로 해서 후자를 26-27의 방법으로 통일하는 방식으로 하는 것이 좋을 것 같다.