ちょっと前までは AppCompatActivity を使用した場合に PreferenceFragment が Support Library の Fragment を継承していないのでそのまま使えず歯がゆい思いをしていたが Android Support Library の Fragment を継承した PreferenceFragmentCompat が登場しその問題が解決された。 しかし古いアプリを移植しようとして RingtonePreference (通知音選択) がそのまま使えない事に気付いた。 SwitchPreferece には SwitchPreferenceCompat が用意されているのに RingtonePreference にはそういったものがない。
仕方が無いので普通の Preference で自分で実装することにした。
呼び出し側
暗黙的インテントを投げることで同機能を実装できる:
mNotificationSound.setOnPreferenceClickListener {
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true)
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_NOTIFICATION_URI)
val existingValue = pref().getString("setting.notificationSound", null)
// Uri として null を指定すると通知音「なし」扱いになることに注意
val uri: Uri? = when {
existingValue == null -> Settings.System.DEFAULT_NOTIFICATION_URI
existingValue.length > 0 -> Uri.parse(existingValue)
else -> null
}
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, uri)
startActivityForResult(intent, 0)
true
}
「Preference の設定がまだされていない場合」「通知音がなし (サイレント) の場合」「通知音が設定されている場合」の 3 通りあることに注意。
その場合分けは上のコードの when
文に示されている。
onActivityResult() 側
暗黙的インテントの戻り値を受け取る為に onActivityResult()
も実装する:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode === 0 && data != null) {
val ringtone = data.getParcelableExtra<Parcelable?>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
pref().edit().putString("setting.notificationSound", ringtone?.let { it.toString() } ?: "").apply()
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
こちらは通知音がなしの場合は null
で渡ってくるので Preference
に空文字で設定しておく。
空文字で無くても null
でさえなければ何でも構わない。
null
だと未設定との区別がつかなくなる。
ちなみに上記 val ringtone
には content://media/internal/audio/media/22
といった感じの CONTENT_URI
表現が入ってくる。
実際に Notification
を鳴らす際にこのまま使うことができる。