【Kotlin】Android で触覚フィードバックの実装をする

今回は、Android で触覚フィードバックの実装をする方法を調査します。

環境

今回のプロジェクトの環境です。

Android Studio 2021.2.1

build.gradle
android {
    compileSdk 32

    defaultConfig {
        ... 省略
        minSdk 29
        targetSdk 32
    }
    ...
}

触覚フィードバックの実装方法

Android における触覚フィードバックについては「触覚フレームワークのための UX の基礎  |  Android オープンソース プロジェクト  |  Android Open Source Project」について詳しく書かれています。

上記のドキュメントによると、HapticFeedbackConstantsVibrationEffectを場合にあわせて使い分けると良いそうです。

HapticFeedbackConstantsを使ってみる

HapticFeedbackConstantsのリファレンスを見ながら実装します。

HapticFeedbackConstantsandroid.ViewperformHapticFeedback()と組み合わせて使います。

STEP.1
import する

これは STEP.2 を書くことで自動で追加されます。

MainActivity.kt
import android.view.HapticFeedbackConstants
STEP.2
フィードバックを実装する

フィードバックは任意のViewよりperformHapticFeedbackを呼び出すことで利用できます。
引数にはHapticFeedbackConstantsを指定します。

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // ボタンタップ時にフィードバックをつける
        binding.button.setOnClickListener {
            it.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
        }
    }
}

VibrationEffect を使ってみる

VibrationEffectのリファレンスを読みながら実装してみます。

STEP.1
import する

これは STEP.2 を書くことで自動で追加されます。

MainActivity.kt
import android.content.Context
import android.os.VibrationEffect
import android.os.Vibrator
STEP.2
フィードバックを実装する

VibrationEffectを利用するためには、システムの Vibrator を取得する必要があります。

VibrationManager について

VibrationManagerは API Level 31 から追加されました。

対してVibratorは API Level 1 から用意されています。

Vibrator のVIBRATOR_SERVICEが deprecated になっているため、今後はVibrationManagerを介してVibratorを利用する必要があります。

Context.java
// Use with getSystemService(String) to retrieve a android.os.Vibrator for interacting with the vibration hardware.
// Deprecated
// Use android.os.VibratorManager to retrieve the default system vibrator.
// See Also:
// getSystemService(String), android.os.Vibrator

@Deprecated
public static final String VIBRATOR_SERVICE = "vibrator";

今回は、API Level 29~32 に対応する形で実装したいので、上記メモよりバージョン分けが必要になります。(参考‘VIBRATOR_SERVICE: String’ is deprecated for API 31

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // ボタンタップ時にバイブレーションをつける
        binding.button.setOnClickListener {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                 val vibratorManager = getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
                 val vibrator = vibratorManager.defaultVibrator
                 val effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
                 vibrator.vibrate(effect)
             } else {
                 val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
                 val effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
                 vibrator.vibrate(effect)
             }
        }
    }
}
STEP.3
Manifest ファイルに Vibrator を使うための許可を書く

Vibratorを使うためには許可が必要になります。

Vibrator.java
@RequiresPermission(android.Manifest.permission.VIBRATE)
public void vibrate(VibrationEffect vibe) {
    vibrate(vibe, null);
}

AndroidManifest.xmlにパーミッションの追加をします。

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.feedbacksample">
    <!-- パーミッションを追加 -->
    <uses-permission android:name="android.permission.VIBRATE" />
    ... 
</manifest>

比較

上記の2つのやりかたで試して実行してみたところ、HapticFeedbackConstants.CONTEXT_CLICKVibrationEffect.EFFECT_CLICKのどちらを使っても、コッとしたフィードバックを得ることができました。

VibrationEffectの方は名前からするとブーッとなりそうですが、コッで実装することができました😌

ブーッとなる通常のバイブレーションはVibrationEffectcreateOneShotcreateWaveformを使うことで実装できるようです。

val vibratorManager = getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
val vibrator = vibratorManager.defaultVibrator
// createOneShot の場合(振動の長さ milliseconds, 振動の強さ 1~255の間で指定)
val effect = VibrationEffect.createOneShot(100, 100)
// createWaveForm の場合(タイミング milliseconds, リピートするかどうか 0(する) or -1(しない))
val effect = VibrationEffect.createWaveform(longArrayOf(100, 200), -1)
vibrator.vibrate(effect)

おわりに

基本的には、ボタンをタップした場合などのフィードバックは手軽にHapticFeedbackConstantsを使えばよさそうです。

また、HapticFeedbackConstantsREJECTはAPI Level 30 で追加されたココッとなるフィードバックですが、それ以前には同様のフィードバックが HapticFeedbackConstants にはありません。

API Level 30 より前に対応したい場合には、VibrationEffect.EFFECT_DOUBLE_CLICKでココッとなるフィードバックを実装することができます。

バイブレーションをさせたい場合や、古いバージョンに対応する場合、少し複雑なフィードバックを利用したい場合にVibrationEffectを選択すると良いかもしれません。