Android Studioとにらめっこしています.アニメを観たりしてお勉強が進みません.
これはUSB COMの簡単なterminalアプリです.
これのFT232のデバドラ部分の動作を知りたいのですが、fragmentを多用していて読解が困難です.お勉強がてら、fragmentの無いアプリに作り替えたろかと思います.また java → kotlin への変換もやったろかと思います.
ーーーー
まずは初歩の初歩でこんなのをkotlinで動かしてみます.
1)OTG USBにarduinoを接続する
2)スマホがUSB挿入を認識する →attachと表示
3)arduinoを外すとスマホが認識する →detachと表示
冒頭でusb-serial-for-androidを参考にしたと書きましたが、USBをattach/detachする段階ではまだusb-serial-for-androidの出番ではありませんので使いません.
どういう意味かというと、usb-serial-for-androidはFT232(COM通信)を動かすものですが、USB attach/detachの段階はandroid OSの仕事だからです.attachされたとOSが検出した後がusb-serial-for-androidの出番になります.
以下でキモの箇所を説明します.
手順1 空のprojectをつくる
最初にandroid studioのnew projectで空のkotlin projectを作ります.
手順2 res/layout/activity_main.xmlを編集
textviewを2ヶ配置し、片方のIDをIDtxt2にしておきます.あとで文字を書き換えるため.
手順3 AndroidManufest.xmlを編集変更するのはactivityのところ.赤字の①②です.
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"> ①
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> ②
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
②について.前提となる知識から述べると、android OSはUSBに何かが接続されたのを検知すると、intentというメッセージをアプリに向かって発します.
当アプリは、intentのうちUSB ATTACHEDを知りたいので、OSに対して「我はUSB ATTACHEDに興味あり」と申告します.だからmanufestにその旨を記述しているんです.それが②です.
①について.当アプリはUSB ATTACHEDを知るといろいろな仕事を始めるわけですが、window画面を切り替えるのか、そうでなく同じwindow画面のままなのか、それを①は指定しているようです.window画面切り替え無しなのでsingkeTaskにしてます.もしもwindow画面切り替えありだと、別のwindow画面へintentが飛んで行ってしまってintentを受信できなくなっちゃうみたいよ.
なおandroid OSでは、window画面のことをactivityと呼びます.
「USB DETACHも知りたいのでは?」と思った人がいるでしょう.それは後で説明します.
device_filterについては後で説明します.
手順4 device_filter.xmlをコピー
話題が出たついでにここで説明します.
android OSは、接続されたUSB機器のVID/PIDをチェックするらしいです.
当アプリが対応するVID/PIDのリストがdevice_filter.xmlです.
USB COM ICは何種類もあるので、それらのVID/PIDのリストになっています.
usb-serial-for-androidは使わないと上で書きましたが、device_filter.xmlだけはusb-serial-for-androidからもらってきます.res/xml/の下に置きます.
手順5 build.gradleを編集
3つある真ん中のやつだと思いますが、赤い行を追加します.これが無いとeditorの補完が効かなくてすごく不便です.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions'
}
手順6 MainActivity.ktを編集
ここがキモのところです.
まずはおなじみonCreate().
①は画面表示をしてます.USB挿入待ちです.
②はあとで説明するdetach処理です.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
IDtxt2.text = "waiting for a USB action" ①
setBroadcastReceivers() ②
}
USB attach処理について.
window画面は、生成されて消されるまでにonCreate()やonDestroy()などの関数がcallされます.そのうちの1つにonNewIntent()があります.
手順3で「USBに何かが挿入されたら教えてくれ」と申告しました.それを受けてOSはUSB挿入時にonNewIntent()をcallして教えてくれます.
intent=ATTACHEDをチェックしたうえで、表示を「attached USB COM」に切り替えます.それ以上の処理は当アプリではやりません.
override fun onNewIntent(intent : Intent) {
if ("android.hardware.usb.action.USB_DEVICE_ATTACHED" == intent.action) {
IDtxt2.text = "attached USB COM"
}
super.onNewIntent(intent)
}
このようにattach処理は簡潔に記述できるのですが、問題はdetach処理です.
detach処理は別のやり方をせにゃいけません.
その理由は、、、
・attach intentは、window画面へ向けて発せられる =onNewIntent()
・detach intentは、ブロードキャストメッセージとして発せられる =onReceive()
という違いがあるからです.うぎゃっ、めんどくせぇ
detach処理はこれです.ブロードキャストメッセージを捕まえるためにここでごにょごにょやってます.美しくないような気がする.せっかくmanufestがあるのにさ.かったるいので解説する気が失せます.
var mUsbReceiver: BroadcastReceiver? = null
fun setBroadcastReceivers() {
mUsbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
IDtxt2.text = "detached USB COM"
}
}
}
val filter = IntentFilter()
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
registerReceiver(mUsbReceiver , filter)
}
これで変更箇所は全部のはずです.
ーーーー
当アプリをスマホ実機で動かしてみます.
↓スマホ上に現れるアイコン
↓起動画面
↓arduinoを抜いたとき
かしこ