画面のスリープを無効にする
カップ麺タイマーをつくっていて気づいたが、今のままだとタイマーが動いているうちにAndroid端末がスリープ状態になってしまい、時間がわからなくなってしまうという致命的な問題がある。
今回はKotlinのコード上で画面のスリープを無効にしたので方法をメモしておく。
環境
開発PC環境
Windows 10
Android Studio 4.1.1
実行Android環境
機種:Xperia X Performance SOV33
Androidバージョン:7.0
アクティビティをFLAG_KEEP_SCREEN_ONに設定する
参考文献の公式ドキュメントを読むと、Activityのコード上でスリープを無効にする方法とレイアウト XML上でスリープを無効にする方法があるが、今回はActivityのKotlinコード上でスリープを無効にする。やり方はいたって簡単で、まず
import android.view.WindowManager
でWindowManagerをインポートして、以下のコードをonCreateの適当な位置に配置するだけ。
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
作成中のカップ麺タイマーでは以下のようにコード中に配置した。
package com.example.cupnoodletimer | |
import android.content.Context | |
import android.media.AudioAttributes | |
import android.media.AudioManager | |
import android.media.SoundPool | |
import android.os.* | |
import android.view.View | |
import android.view.WindowManager | |
import android.widget.Button | |
import android.widget.ImageView | |
import android.widget.TextView | |
import androidx.annotation.RequiresApi | |
import androidx.appcompat.app.AppCompatActivity | |
class MainActivity : AppCompatActivity() { | |
val TIMERTIME: Long = 180000; | |
lateinit var timerText: TextView | |
lateinit var timer: CountDownTimer | |
var isRunning: Boolean = false; | |
lateinit var soundPool: SoundPool | |
var soundAlarm = 0 | |
@RequiresApi(Build.VERSION_CODES.LOLLIPOP) | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
val startButton: Button = findViewById(R.id.buttonStart) | |
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator | |
val audioAttributes = AudioAttributes.Builder() | |
.setUsage(AudioAttributes.USAGE_ALARM) | |
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) | |
.build() | |
soundPool = SoundPool.Builder() | |
.setAudioAttributes(audioAttributes) | |
.setMaxStreams(1) | |
.build() | |
val imageView = findViewById<ImageView>(R.id.imageView) | |
imageView.setImageResource(R.drawable.cup_ramen) | |
imageView.visibility = View.INVISIBLE | |
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) | |
startButton.setOnClickListener { | |
if (isRunning) { | |
timer.cancel() | |
setTime(TIMERTIME) | |
isRunning = false | |
startButton.text = "START" | |
imageView.visibility = View.INVISIBLE | |
} else { | |
soundAlarm = soundPool.load(this, R.raw.alarm, 1) | |
timer = object : CountDownTimer(TIMERTIME, 1000) { | |
override fun onTick(millisUntilFinished: Long) { | |
setTime(millisUntilFinished) | |
} | |
override fun onFinish() { | |
setTime(0) | |
isRunning = false | |
startButton.text = "RESTART" | |
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | |
val vibrationEffect = VibrationEffect.createOneShot(5000, VibrationEffect.DEFAULT_AMPLITUDE) | |
vibrator.vibrate(vibrationEffect) | |
} else { | |
vibrator.vibrate(5000) | |
} | |
val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager | |
val alarmVol: Float = am.getStreamVolume(AudioManager.STREAM_RING).toFloat() | |
var alarmMaxVol: Float = am.getStreamMaxVolume(AudioManager.STREAM_RING).toFloat() | |
var setVol: Float = (alarmVol / alarmMaxVol).toFloat() | |
soundPool.play(soundAlarm, setVol, setVol, 0, 0, 1.0f) | |
imageView.visibility = View.VISIBLE | |
} | |
} | |
timer.start() | |
isRunning = true | |
startButton.text = "RESET" | |
imageView.visibility = View.INVISIBLE | |
} | |
} | |
} | |
private fun setTime(t: Long) { | |
timerText = findViewById(R.id.textViewTime) | |
var time: Long = t | |
var minutes: Long = (time / 1000) / 60 | |
var seconds: Long = (time / 1000) % 60 | |
timerText.setText("%d:%02d".format(minutes, seconds)) | |
} | |
} |
実機で確認してみて、アプリ起動中はスクリーンがスリープにならないことを確認した。なお、ドキュメントにも書いてあるが明示的にFLAG_KEEP_SCREEN_ONをクリアしなくても、アプリがバックグラウンドに移動するか、またはフォアグラウンドに戻ってくると、ウィンドウ マネージャーが適切な処理が行われるようにしてくれるとのこと。
参考文献
今回は以下のサイトを参考にさせて頂きましたm(_ _)m
デバイスの起動状態を維持する | Android デベロッパー | Android Developers
Androidアプリをつくって遊ぼう日記まとめ
以下にAndoirdアプリで遊んでみた軌跡を残しています。興味があればのぞいてみてください。