Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

Vibratorでカウントダウン終了時に振動でお知らせ!

 どうも!LSSです!

 

 KotlinでAndroidアプリ開発を練習中です。

 

 今回は、前々回前回、作成した簡易カウントダウンタイマー&ストップウォッチ
カウントダウン終了時に振動でもお知らせする機能を作ってみます!

 振動させる事自体は簡単ですが、AndroidManifest.xmlの編集や、Androidのバージョン判定なんかも必要になるのがちょっと面倒かな、って感じです。

 

 

今回の肝!

 Vibratorを使うにあたって必要な記載です。

 

 AndroidManifest.xml 内に記載

<uses-permission android:name="android.permission.VIBRATE"></uses-permission>

 

Vibratorと振動のパターンを、Activity直下で宣言

lateinit var vb0:Vibrator
val vbpt0= longArrayOf(0,150,50,150,50,150,50,350,50,350,50,350,50)

 

Vibratorを、onCreate内で設定

vb0= getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

 

端末にVibrator機能があるかどうかを判定

if(vb0.hasVibrator()){

 

振動させる。振動させたいところに記載

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
vb0.vibrate(VibrationEffect.createWaveform(vbpt0,0))

}else{
vb0.vibrate(vbpt0,0)

}

※注意!一行めのBuild.VERSION_CODES.Oの末尾はゼロじゃなくてオーです。

 

Vibratorを止める。止めたいところとonDestroy内に記載

vb0.cancel()

 

 振動させる、の部分が少しややこしい記載になっています。

というのも…実際に振動させる部分は1行なのですが、Android8.0から仕様が変わってしまい、Android7.0までの書き方とAndroid8.0以降の書き方、2通り用意しているためです。

 また、AndroidStudio上では後者のvibratevibrateと、取り消し線の入った状態になってしまいますが、これは上記理由により非推奨扱いだからです。

 

AndroidManifest.xml について

 AndroidManifest.xmlは、そのアプリの情報(端末の特殊な機能を使っていいか?など)を記載する、特別で重要なファイルです。

 このブログで登場するのは多分初めてですが、Vibratorを利用するには許可設定を書き足す必要となります。

 

f:id:little_strange:20191028012428p:plain

AndroidStudioの画面左、「app」「manifests」と開いていった中にあります!

 この、AndroidManifest.xmlをダブルクリックすると、右の編集画面に出てきます。

 

f:id:little_strange:20191028012807p:plain

 この、<applicationの手前あたりに入れてやるといいみたいです。

 

 

f:id:little_strange:20191028014422p:plain

こんな感じですね。

 

 

 

 

コード全文

Vibrator関連赤文字にしています。

また、vb0vbpt0は任意の名前(好きに変えちゃってOKな部分)です。

 


package jp.littlestrangesoftware.mytech

import android.content.Context
import android.content.pm.ActivityInfo
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import android.os.*
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_timer.*
import java.util.*

class timerActivity : AppCompatActivity() {

var cld0=Calendar.getInstance() // 計測開始時の時刻値 保管用
var cld1=Calendar.getInstance() // 現在の時刻値 保管用
var tflag=false // タイマー動作中はtrueになるフラグ
var cntF=true // カウントダウン未終了フラグ

var CntT=180 // カウントダウン用の時間を秒で指定

lateinit var ur0:Uri // Uriを宣言
lateinit var rt0:Ringtone // Ringtoneを宣言

lateinit var vb0:Vibrator // Vibratorを宣言
val vbpt0= longArrayOf(0,150,50,150,50,150,50,350,50,350,50,350,50)
// Vivratorのパターンを作成

val hnd0=Handler() // Handlerを作成
val rnb0=object:Runnable{
override fun run() {
cld1.timeInMillis=System.currentTimeMillis() // 現在の時刻値をミリ秒で取得

var i=CntT+((cld0.timeInMillis-cld1.timeInMillis)/1000).toInt() // 残り秒数

// カウントダウンが完了している場合
if (i<0) {
i = 0

// カウントダウン終了後に1回だけ行う
if (cntF){
cntover() // 処理内容を書いた別のfunを呼び出す
cntF=false // フラグをfalseにする事で連続動作を防止
}
}
// カウントダウンタイマーの表示
tvCntD.text="%02d:%02d".format(i/60,i%60)

// ストップウォッチの表示
tv0.text="%.2f".format((cld1.timeInMillis-cld0.timeInMillis).toFloat()/1000)

hnd0.postDelayed(this,10) // 0.01秒後にこの処理を再度呼び出し
}
}

// カウントダウン終了後に行う処理
fun cntover(){
rt0.play() // Ringtone(音)を鳴らす

// 端末にVibrator機能がある場合
if(vb0.hasVibrator()){
vb0run()
}
}

// Vibratorを振動させる
fun vb0run(){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ // Android8.0以降の場合
vb0.vibrate(VibrationEffect.createWaveform(vbpt0,0))

}else{ // Android8.0未満の場合
vb0.vibrate(vbpt0,0)

}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_timer)
requestedOrientation =ActivityInfo.SCREEN_ORIENTATION_PORTRAIT // 縦画面に固定

ur0=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM) // uriを設定
rt0=RingtoneManager.getRingtone(this,ur0) // Ringtoneを設定

vb0= getSystemService(Context.VIBRATOR_SERVICE) as Vibrator // Vibratorを設定

}


// START・STOPボタンを押した時の処理
fun btSclk(v:View){
if (tflag) { // tflagはタイマー作動中はtrue、停止中はfalse

// 作動中にSTOPが押された場合の処理
tflag=false
btS.text="START"
rt0.stop() // Ringtone(音)を止める
vb0.cancel() // Vibratorを止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル

}else{

// 停止中にSTARTが押された時の処理
tflag=true
btS.text="STOP"
cntF=true


cld0.timeInMillis=System.currentTimeMillis() //STARTが押された時の時刻値をcld0にセット
hnd0.post(rnb0) // handlerタイマー処理を開始

}
}

override fun onDestroy() {
rt0.stop() // Ringtone(音)を停止
vb0.cancel() // Vibratorを止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル
super.onDestroy()
}

}

 

 

 

振動パターンについて

val vbpt0= longArrayOf(0,150,50,150,50,150,50,350,50,350,50,350,50)

 …と、長々と書いていますが、この数値で振動のパターンを設定しています。

Long型のArray(配列)で、配列の内容は整数であればいくつでも書いてOKです。

一つ目の数字(この例では0)は、振動を開始するまでの時間(ミリ秒)
二つ目の数字(この例では150)は、最初に振動する時間(ミリ秒)
三つ目の数字(この例では50)は、その後、振動しない時間(ミリ秒)
四つ目の数字(この例では150)は、また振動する時間(ミリ秒) 

…という具合に、振動しない・振動する・振動しない・振動する・振動しない…と、OFFとONの時間を交互に書いていく感じです。

 ちなみに、今回の例では、
「タ、タ、タ、タン、タン、タン」
というリズムを表現しています。

 

 

振動回数について

 実際に振動させる場面で、8.0以降の場合未満の場合

(vbpt0,0)

という指定があります。

 一つめのvbpt0は予め用意した振動パターンを表すLongArrayで、その後の0
その振動パターンを繰り返すなら0、繰り返さないなら-1
になります。

 

 

 

 

今回、やってみて思ったのは…

 Androidの進化が速くて、すぐに情報が古くなるなーとは前から思っていたのですが、今なお8.0未満の端末もたくさんあるのに、今回実際に
それ用のコードがもう既に非推奨扱いになってるのに触れて、なんだかなぁ、と思いましたw

 勉強しはじめた時に、参考にしたAndroidStudioのバージョンの現行のものとの違いで戸惑ったりしたので、
自分のこのブログも新しい環境での手順を書いてる分、いくらか存在価値があるかな
みたいな事も思ったのですが、これもまたすぐに古くなりそうですねw
実際、ブログ始めてから今までの短い期間の中でleyout_weightのデフォルトがちょっと変わったっぽいし^^;

 

 あ、そうそう。

 AndroidStudio付属のエミュレータでは色々なAndroidのバージョンを切り替えて試せますが、振動はエミュレータでは試せません。

 今回、自分が実機で確認したのは、8.09.05.0にて動作を確認しています。

 

てなところで、今回はここまで!

次回もまた、よろしくお願いします^^