/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.deskclock.settings import android.annotation.TargetApi import android.app.NotificationManager import android.content.Context import android.content.Context.AUDIO_SERVICE import android.content.Context.NOTIFICATION_SERVICE import android.database.ContentObserver import android.media.AudioManager import android.media.AudioManager.STREAM_ALARM import android.os.Build import android.provider.Settings import android.util.AttributeSet import android.view.View import android.widget.ImageView import android.widget.SeekBar import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import com.android.deskclock.R import com.android.deskclock.RingtonePreviewKlaxon import com.android.deskclock.Utils import com.android.deskclock.data.DataModel class AlarmVolumePreference(context: Context?, attrs: AttributeSet?) : Preference(context!!, attrs) { private lateinit var mSeekbar: SeekBar private var mPreviewPlaying = false override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) val context: Context = getContext() val audioManager: AudioManager = context.getSystemService(AUDIO_SERVICE) as AudioManager // Disable click feedback for this preference. holder.itemView.setClickable(false) // Minimum volume for alarm is not 0, calculate it. val maxVolume = audioManager.getStreamMaxVolume(STREAM_ALARM) - getMinVolume(audioManager) mSeekbar = holder.findViewById(R.id.alarm_volume_slider) as SeekBar mSeekbar.setMax(maxVolume) mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM) - getMinVolume(audioManager)) (holder.findViewById(R.id.alarm_icon) as ImageView) .setImageResource(R.drawable.ic_alarm_small) onSeekbarChanged() val volumeObserver: ContentObserver = object : ContentObserver(mSeekbar.getHandler()) { override fun onChange(selfChange: Boolean) { // Volume was changed elsewhere, update our slider. mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM) - getMinVolume(audioManager)) } } mSeekbar.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { context.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, volumeObserver) } override fun onViewDetachedFromWindow(v: View) { context.getContentResolver().unregisterContentObserver(volumeObserver) } }) mSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { if (fromUser) { val newVolume = progress + getMinVolume(audioManager) audioManager.setStreamVolume(STREAM_ALARM, newVolume, 0) } onSeekbarChanged() } override fun onStartTrackingTouch(seekBar: SeekBar?) { } override fun onStopTrackingTouch(seekBar: SeekBar) { if (!mPreviewPlaying) { // If we are not currently playing, start. RingtonePreviewKlaxon .start(context, DataModel.dataModel.defaultAlarmRingtoneUri) mPreviewPlaying = true seekBar.postDelayed(Runnable { RingtonePreviewKlaxon.stop(context) mPreviewPlaying = false }, ALARM_PREVIEW_DURATION_MS) } } }) } private fun onSeekbarChanged() { mSeekbar.setEnabled(doesDoNotDisturbAllowAlarmPlayback()) } private fun doesDoNotDisturbAllowAlarmPlayback(): Boolean { return !Utils.isNOrLater || doesDoNotDisturbAllowAlarmPlaybackNPlus() } @TargetApi(Build.VERSION_CODES.N) private fun doesDoNotDisturbAllowAlarmPlaybackNPlus(): Boolean { val notificationManager = getContext().getSystemService(NOTIFICATION_SERVICE) as NotificationManager return notificationManager.getCurrentInterruptionFilter() != NotificationManager.INTERRUPTION_FILTER_NONE } private fun getMinVolume(audioManager: AudioManager): Int { return if (Utils.isPOrLater) audioManager.getStreamMinVolume(STREAM_ALARM) else 0 } companion object { private const val ALARM_PREVIEW_DURATION_MS: Long = 2000 } }