0

Moto360にBluetoothデバッグでアプリを書き込む

ふつうAndroid Wear用に作った自作アプリをWearに書き込む時は、充電用のUSBポートでPCと接続すればAndroid Studioのターゲットデバイスに表示されるらしい。しかしMoto360はQiによる無線充電なので、USBポートが無い。

PC–(USB)–スマホ–(Bluetooth)–Moto360 と接続すれば、スマホを中継して自作アプリを書き込んだりlogcatを見たりできる。

参考:Debugging over Bluetooth | Android Developers

手順


スマホ側で、「開発者向けオプション」を開いて(無ければ端末情報のバージョン情報を7回タップで出る)「USBデバッグ」を有効にする

Moto360の「開発者向けオプション」を開いて(こっちも無ければWearのバージョン情報7回タップ)「Bluetooth経由でデバッグ」を有効にする

スマホの「Android Wear」アプリの設定で、「Bluetooth経由のデバッグ」を有効にする。「ホスト:未接続」と「ターゲット:接続済み」になればok

AndroidStudioでDevicesにスマホが認識されているか確認する。なければそのままUSB抜き差しすると認識されるはず。


ターミナルで以下を実行
adb forward tcp:4444 localabstract:/adb-hub
adb connect localhost:4444

するとスマホのAndroid Wearアプリで「ホスト:接続済み」「ターゲット:接続済み」になる。
PCのAndroid StudioでもMoto360が認識されているはず

あとは普通にWear用のプロジェクトを作って書き込む時にMoto360を選べば書き込める。

書き込むとこうなって4分ぐらい待たされるが、気長に待つ。
Waiting for device.
Target device: motorola-moto_360-localhost:4444
Uploading file


4分待つの長いし、何もプログレスとか出ないのですごい不安になる。USB接続だともっと速いんだろうか・・・


deployment – Moto 360 Deploying from Android Studio extremely slow – Stack Overflowを見ると、「書き込みに10分かかるんだけど」という質問に対して「adb debugを再起動するとよくなる」っていう解答がある。
試しに再起動しても3,4分かかった。

0

Android4.4のメーラでさくらレンタルサーバのメールが読めない件

たしか6月ごろのAndroidのOS 4.3から4.4へのアップデートだったと思う。メール読みたくないので放置してた。

さくらレンタルサーバのIMAPメールの本文が読めなくなった。件名や差出人は見れる。
本文を読もうとすると「不明なエラー」と表示され、メールヘッダを見ようとすると強制終了する。

さくら以外のサーバーのメールは見れるのと、
Nexus5とNexus7両方同時に見れなくなって、OSアップデートが来ないauのHTC One J (Android 4.1.1)は読めてるのでAndroidのメーラーがおかしくなったんだと思う。


対処

K-9 mailインストールしたら万事解決した。

K-9には定期的にメールサーバーにチェックに行く機能はデフォルトでOFFになっていて(ONにもできるが)、
代わりにIMAP4 IDLEが使える。
TCP接続しっぱなしにして新着ごとにEXISTSが送られてくるので、サーバにメール届いたらしたらすぐスマホに通知される。

0

AndroidScala用iBeaconライブラリに領域判定機能つけた

だいぶ書き忘れてたけど3週間ぐらい前に作った気がする

https://github.com/shokai/iBeacon-AndroidScala


前:AndroidでiBeaconを読む(Scalaで)


onRegionでRSSIの範囲を指定してevent登録できる
-70から-50、端末にもよるけどだいたい15メートル以上20メートルぐらいに入った時にcallbackされる。

// UUID, major, minor, RSSI range, callback
iBeacon.onRegion("805D6740-F575-492A-8668-45E553EB9DF2", "0001", "0001", Range(-70,-50), (beacon:Beacon) => {
Log.v("iBeacon", s"region(-70~-50) UUID=${beacon.uuid} RSSI=${beacon.rssi}")
})

UUID, major, minorはそれぞれnullを与えると何にでも反応するようになる

onRegionのラッパーでonFar, onNear, onImmediateというのがあって、それぞれ電波とどかなくなるギリギリ30メートルぐらい、割と近い数メートル、すごく近い数十センチでcallbackする。
iBeacon.onFar("805D6740-F575-492A-8668-45E553EB9DF2", "0001", "0001", (beacon:Beacon) => {
Log.v("iBeacon", s"far: ${beacon.uuid}")
})

iBeacon.onNear("805D6740-F575-492A-8668-45E553EB9DF2", "0001", "0001", (beacon:Beacon) => {
Log.v("iBeacon", s"near: ${beacon.uuid}")
})

iBeacon.onImmediate("805D6740-F575-492A-8668-45E553EB9DF2", "0001", "0001", (beacon:Beacon) => {
Log.v("iBeacon", s"immediate: ${beacon.uuid}")
})

これらを使って研究室のドアに近づいたらカギが開くようにしたりしてる。

0

AndroidでiBeaconを読む(Scalaで)

前:ScalaでAndroidアプリを作る


iBeaconをAndroidで読んで、ビーコンが現れたらNotificationを出すとかできるライブラリを作った。
advertiseパケットを自前でparseしてiOSのSDKで使われてるのと同じフォーマットの16進コードに変換してるけど、scalaなので15行ぐらいで書けた。

https://github.com/shokai/iBeacon-AndroidScala

先週研究会でspammerっていう人がiBeaconの仕組みとかをまとめて発表してくれた。
へぇーと思ったのでMyBeacon買って土日にAndroid用のライブラリを作った。

Javaは冗長でつらいのでScalaで書いたけど、Scalaもライブラリの配信方法が.classをjarに固めてmaven使うとか冗長でつらい。どうすればいいんだ。なんでコンパイル前のscalaスクリプトのまま流通させないのか理解できない。


使い方


詳しくはGitHubのREADMEに書いた。

Activityから起動する例
import org.shokai.ibeacon.{IBeacon, Beacon};

class MainActivity extends Activity{

lazy val iBeacon:IBeacon = new IBeacon(this)

override def onCreate(savedInstanceState:Bundle){

// ビーコンを発見した時にcallbackされる
iBeacon.onDiscover((beacon:Beacon) =>
Log.v("iBeacon", s"UUID=${beacon.uuid} Major=${beacon.major} Minor=${beacon.minor} RSSI=${beacon.rssi}")
)

}

}


AndroidManifest.xml
<manifest>
<application> ~~ (略) ~~ </application>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
</manifest>

とても簡単でよい。
onBeaconというコールバックもあって、これは全てのビーコンパケットをコールバックしてくる。
ビーコンは常に電波を発信しまくっているので、onBeaconイベントはものすごい勢いで呼ばれる。
コールバックされるBeaconオブジェクトのrssiプロパティで受信信号強度が取れるので、距離もなんとなく計れる。
だいたい見通し25メートルぐらいで-90、接触するぐらい近いと-20〜-10とかになる。

なお1度呼ばれた同じビーコンのonDiscoverが再び呼ばれるのは、そのビーコンの信号が5秒間無くなって再び現れた時。


サンプルアプリ


信号を読むやつapk


ビーコンを見つけたら通知を出すサービス(電源ONしたら自動起動する)

これ改造すると、猫にビーコンつけて近寄ってきたらエサくれ通知を出すとか、自分が家に近づいたらカギが開くとか簡単に作れる。


iBeaconとは

Appleが考えたBluetoothデバイスの存在通知手法で、ずっと電波出し続けているデバイス(ビーコン)をいろいろな場所に設置しておいて、その電波をスマホが検知すると「〜〜というデバイスがあるのでアプリを起動しますか?」のような通知を出す。
最近のiOSアプリ持ってないので実物を見たことがないんだけどそんな感じのはず。

実装としてはBluetooth LE (ローエナジー) のadvertiseパケットの末尾にビーコンのUUIDやmajor,minorといった識別子を突っ込んでいるもので、そんなに凄い事をしているわけではない。
なのでAndroidでもadvertiseパケットを見て、バイナリをparseしたらUUIDとか取り出せた。

インスタントメッセンジャーアプリの名前欄で会話してる人とかいるけど、そういうのに近い。


1800円のMyBeaconを3個買って、研究室に設置した。


参考

iOS – AndroidでiBeacon信号を受信してみよう – Qiita

0

ScalaでAndroidアプリを作る

普段Javaで書いている部分をScalaで書けるようになった。
Javaだと、文字列や複雑なデータ構造を処理したり、関数プログラミングがしづらい。lambda無いし。そういう部分だけでもScalaでやりたい。

https://github.com/pfn/android-sdk-pluginというフレームワークを使って、既存のAndroidアプリのプロジェクトでScalaとJavaを混ぜこぜに書けるようにする方法を説明する。

全体の簡単な手順

  1. homebrewでscalaとsbtをインストールする
  2. Androidのプロジェクトを普通に作る or 既存のAndroidプロジェクトを用意する
  3. sbtで使う設定ファイル3つを配置する
  4. sbt初回起動時に必要なライブラリがインストールされて、Androidプロジェクトとsbtプロジェクトが共存した状態になる
  5. sbtでandroid:packageすると、1つのapkになる

という感じ。


参考にしたサイト

この2つしか読んでいない。
もし俺の記事でよくわからない箇所があったら、下手にググって余計なの読む前に下の2つをちゃんと読んだ方がいい。
今回使っている「android-sdk-plugin」と似たような位置づけのフレームワークとして、「android-plugin」と「scaloid」がある。
前者は少し古い物でこれを参考にandroid-sdk-pluginが作られた。
後者はandroid-sdk-pluginの上にさらに乗せるライブラリで、XMLでのレイアウトをscalaだけで書くようになっていたりしていて、既存のAndroidプロジェクト内でScalaも使うという用途にはちょっと向いていないと思った。

このように似たライブラリがあるので、安易に「scala android」とかでググると関係ない情報を読むことになる。公式ドキュメント重要。


試しに作ったもの

ここに置いた
https://github.com/shokai/ScalaAndroidTestApp
「つらい」が「っらぃ」のようになるだけのアプリ。
Scalaっぽい(Javaでは書きにくい)文字列やMapの処理と、Javaで書かれているAndroid SDKのGUI機能両方を使ってみたかったのでやってみた。
元ネタはScalaをちょっと勉強したに書いた研究室の練習問題。

MainActivityのコードを見ればわかるが、scalaだと辞書作って1文字ずつチェックして置換するような処理はJavaよりも書きやすい。


Androidアプリの新規作成

Android開発環境をインストールしなおしたに書いた手法でHomebrewでAndroid SDKをインストールした。
Eclipseは入れていない。emacsとterminalだけで開発する。

brew install android-sdk


まずプロジェクトのビルドターゲットを確認してから
android list
id: 3 or "android-18"
Name: Android 4.3
Type: Platform
API level: 18
Revision: 2

新規プロジェクトを作る。とりあえずビルド、端末にインストールまでする
android create project --target "android-18" --name ScalaTestApp --path `pwd` --activity MainActivity --package org.shokai.scalatestapp
android update project --path `pwd`
ant debug
adb install -r bin/ScalaTestApp-debug.apk


Scalaが使えるようにする

antの代わりにsbtを使う。

brew update
brew install scala sbt
scala 2.10.2 と sbt 0.13.0 がインストールされた。
sbt(simple-build-tool)は名前に反してシンプルではなく、node.jsのnpmに近い多機能な物で、
  • main()があるファイルを適当に探して、実行してくれる
  • scalaのライブラリのパッケージ管理、バージョン固定
  • 実行するscalaインタプリタのバージョン指定
  • ScalaとJavaを共存させ、.classなどの位置を気にせずに混ぜこぜで実行できる
  • Javaの場合は.classなどの中間ファイルも適当な場所に生成、管理してくれる
  • コマンド名の頭に「~ 」(チルダスペース)を付けると、ソースファイルの変更を検知してコマンドを再実行してくれる
などの機能がある。
いくつかはscala android-sdk-pluginがやってくれている機能なのかもしれない。
まだsbt使い込んでいないから完全に把握しきれていない。

sbt自体がなかなか面白いプロダクトなので、Getting Started — sbt Documentationを読んだ方がいい。


Androidプロジェクト内にファイルを3つ置いてsbt起動すればscalaが使えるようになる。
それぞれのファイル内でAndroid SDKやsbtのバージョンを指定しているので注意。

build.sbt (1行ずつ空けなければならないらしい)
import android.Keys._

android.Plugin.androidBuild

name := "ScalaTestApp"

platformTarget in Android := "android-18"

run <<= run in Android

install <<= install in Android

project/build.properties
sbt.version=0.13.0

project/plugin.sbt
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.0.6")


sbt起動
sbt
sbtのコンソールが起動し、自動的に依存ファイルがインストールされてscalaが使えるようになる。

とりあえずJavaのままだけどビルドする。sbtのコンソール内で
compile
が通ればok。


JavaをScalaに書きなおす

MainActivity.javaをMainActivity.scalaにリネームし、書き直す。
package org.shokai.scalatestapp;

import android.app.Activity;
import android.os.Bundle;

class MainActivity extends Activity{
override def onCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

sbtコンソールでビルドする。
android:package-debug
同じ名前の.javaと.scalaが混在しているとビルドが通らないが、別名なら混在していていい。


adbで実機にインストールする
adb install -r bin/ScalaTestApp-debug.apk
scalaでアプリが書けましたね。



大文字ひらがなを小文字ひらがなに変換するアプリを作る

レイアウトのXMLとScalaで書きなおしたMainActivityを編集する。


res/layout/main.xml にボタンとEditTextを追加
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="@+id/editTextSource"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textShortMessage" />
<Button
android:id="@+id/btnRun"
android:text="小文字に変換"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
<TextView
android:id="@+id/textViewResult"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="result here" />
</LinearLayout>


src/org/shokai/scalatestapp/MainActivity.scala
package org.shokai.scalatestapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.view.View;
import android.view.View.OnClickListener;

class MainActivity extends Activity{

var editTextSource:EditText = _
var textViewResult:TextView = _
var btnRun:Button = _

override def onCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

editTextSource = findViewById(R.id.editTextSource).asInstanceOf[EditText]
textViewResult = findViewById(R.id.textViewResult).asInstanceOf[TextView]
btnRun = findViewById(R.id.btnRun).asInstanceOf[Button]

btnRun.setOnClickListener( new OnClickListener(){
override def onClick(v:View){
val source = editTextSource.getText().toString()
trace(s"source: $source")
val result = kana_downcase(source)
trace(s"result: $result")
textViewResult.setText(result)
}
})
}

def kana_downcase(str:String):String = {
val chars = scala.collection.immutable.Map[String,String](
"あ" -> "ぁ",
"い" -> "ぃ",
"う" -> "ぅ",
"え" -> "ぇ",
"お" -> "ぉ",
"つ" -> "っ",
"よ" -> "ょ",
"わ" -> "ゎ")

return str.split("").
map(c =>
if(chars.contains(c)) chars(c) else c
).mkString
}

def trace(message:String){
Log.v("ScalaTestApp", message)
}
}
scalaなので、変換表を気軽にMapで作って1つずつチェックして置換して結合とか書けるし、
いちいちtoString()しないで s"$変数名" で変数展開して文字列に埋め込んだりできて便利だった。

ビルドするとこうなる


.gitignore

Android SDKは中間ファイルをたくさん生成するので、Gitにコミットする時にディレクトリそのままaddするとdiffが酷い状態になる。
さらにscala android-sdk-pluginも中間ファイルを生成する。
必要ないファイルはignoreしておくべき。

.gitignore
.DS_Store
*.log
*~
*#*
*.class
.classpath
.project
bin
build.xml
local.properties
proguard.cfg
.settings
target
project/target
tmp
local.propertiesなどもcommitしないようにしているので、リポジトリをcloneしなおして来た直後は
android update project --path `pwd`
を実行して、それぞれの環境に合わせたAndroid SDKのパスを生成しなおすようにしている。
こういうビルド作法はREADMEに書いておくといい