2014年10月23日木曜日

簡単だと思っていたのに、結構ハマったのでメモとして残しておきます

参考にしたのは、次の2つの記事です




重要なのは2点だけ
  1. GridViewの行になっているレイアウトのbackgroundに?android:attr/activatedBackgroundIndicatorを設定する
  2. activatedBackgroundIndicatorをThemeでオリジナルのものに変更する
ただし、APIレベル11以降のお話です

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="?android:attr/activatedBackgroundIndicator"
>
<TextView
 android:layout_width="fill_parent"
 android:layout_height="40dip"
 android:gravity="center"/>
</LinearLayout>


Theme(style.xml)

<style name="AppTheme" parent="AppBaseTheme">
      <item name="android:activatedBackgroundIndicator">@drawable/grid_background</item>
</style>


grid_background.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true" android:drawable="@color/green" />
    <item android:state_selected="true" android:drawable="@color/green" />
    <item android:state_pressed="true" android:drawable="@color/green" />
    <item android:state_checked="true" android:drawable="@color/green" />
    <item android:drawable="@color/blue" />
</selector>


これはメモなので、詳細は上にあげたサイトを見るのが良いと思います


2014年6月24日火曜日

AndroidでiBeacon(2)

前回「AndroidでiBeacon(1)」の続きで、今回は検出したBeaconから情報を取得します
取得するのは

  • UUID
  • major
  • minor
  • 電波強度

の4つです

端末を検出したらコールバックされるBluetoothAdapter.LeScanCallbackのonLeScanを変更していきます

onLeScanには3つの引数があり、UUIDなどの情報は第3引数のbyte配列に入っています

その配列は次のようになっています

データ構造


01ブロック目のバイト数
1
フラグ
2
32ブロック目のバイト数
4AD Type
5
会社ID
0x00CがAPPLE
6
7データタイプ0x02がiBeacon
8iBeaconデータのバイト数
9
UUID
16バイト
~
24
25
major
4バイト
26
27
minor
4バイト
28
29電波強度距離計算する際の基準値として利用

データを取得

onLeScanの中身を変更しています


    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            if (scanRecord.length > 30) {
                //このif文でiBeaconかどうかを判別
                if ((scanRecord[5] == (byte) 0x4c) && (scanRecord[6] == (byte) 0x00)
                        && (scanRecord[7] == (byte) 0x02) && (scanRecord[8] == (byte) 0x15)) {
                    String uuid = getScanData(9, 24, scanRecord);
                    String major = getScanData(25, 26, scanRecord);
                    String minor = getScanData(27, 28, scanRecord);
                    String strength = String.valueOf(scanRecord[29]);
                    Log.d("BeaconSample", "-----------------------------");
                    Log.d("BeaconSample", "uuid::" + uuid);
                    Log.d("BeaconSample", "major::" + major);
                    Log.d("BeaconSample", "minor::" + minor);
                    Log.d("BeaconSample", "strength::" + strength);
                    Log.d("BeaconSample", "rssi::" + rssi);
                }
            }
        }
    };

    public String getScanData(int start, int end, byte[] scanRecord) {
        StringBuilder result = new StringBuilder(end - start);
        for (int i = start; i <= end; i++) {
            result.append(convertHex(scanRecord[i] & 0xff));
        }
        return result.toString();
    }

    public String convertHex(int i) {
        char hexArray[] = {
                Character.forDigit((i >> 4) & 0x0f, 16), Character.forDigit(i & 0x0f, 16)
        };
        return new String(hexArray).toUpperCase();
    }

データの取得は以上です

配列の中にある電波強度は基準値なので変化しません
実際の電波強度は第2引数のrssiになります



次回は、Androidで使えるライブラリを探してライブラリを利用方法などを紹介したいと思います

2014年6月23日月曜日

AndroidでiBeacon(1)

Beaconを貸して頂いたので、これら何回かに分けてAndroidでiBeaconを触ってみる記事を書いてみようと思います

iBeaconについては、いろいろと情報があると思いますので説明は省きます
iBeaconって何?という方は、まずGoogleなどで検索してみてください

必要なもの


BLEに対応したAndroid 4.3以上の端末
Beacon(今回はBeacon USBを利用)

Beaconの設定


最初にBeaconの設定をしておきます
設定する情報は、Proximity UUID(以降、UUIDと略),Major, Minorとありますが、どの情報を使って検出したいBeaconを判別するかによりますので、1台だけならUUIDだけでも良いかもしれませんし、1台でもMajorまで設定しておいても良いかもしれません

今回は、UUID,Major,Minorを全て設定しておきます

※今回利用するBeaconUSBに専用のアプリがまだ無いので、HPに記載されている設定マニュアルにあるとおり「BLE Utility」というアプリを使って設定します。このアプリはiOS用なのでAndroid端末しかない場合は、別途BLがで利用できる設定アプリを探してください



Androidアプリを作る


前提条件


BluetoothはONになっていることとする(ONにしたり、利用可否のチェックは省く)

参照


コードは、Androidの公式情報を基にして書いていきます
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html



Permission


BLUETOOTHを利用するための権限を設定します。

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

アプリの中でBluetoothのON/OFFなど操作を行う場合にはBLUETOOTH_ADMINの権限も必要となります BLUETOOTHの操作も行いたい場合は、以下の2つを設定してください
※あとで検証したら、BLUETOOTH_ADMINを指定しないと端末が検出できないことが判りました。BLUETOOTH_ADMINは必須のようです

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

BLEに対応した端末だけにインストールを許可したい場合には、以下のuses-featureを設定してください

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

BluetoothAdapterを取得する

BluetoothAdapterはBluetoothManagerから取得します
    private BluetoothAdapter mBluetoothAdapter;
public class MainActivity extends Activity {

    private BluetoothAdapter mBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
    }

}

BLE端末を検出する

BLEを検出する処理を追加します
検出は、BluetoothAdapterのstartLeScanで実行されます
検出が終了するとstartLeScanの引数で指定したコールバックのメソッドが呼び出されます

BLEの検出は何度も繰り返し行われるため、ハードウェア的に問題となるため1秒たったらスキャンを停止する(stopLeScan)ようになっています
※コールバック用のメソッドは後述
    @Override
    protected void onResume() {
        super.onResume();
        scanLeDevice(true);
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }



BLEの検出結果を処理する


BLEの検出が終わるとstartLeScanで指定したコールバックのメソッドが呼び出されますので、その中で検出結果を解析します
今回はデバイスの名前とアドレスをログに出力してみます

    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
            Log.d("BeaconSample", "name::" + device.getName());
            Log.d("BeaconSample", "address::" + device.getAddress());
            Log.d("BeaconSample", "------------------------------");
        }
    };

スキャンの停止


 アプリが停止しているときは、スキャンを停止するようにしましょう
    @Override
    protected void onPause() {
        super.onPause();
        scanLeDevice(false);
    }


今回はここまで。
次回は、結果からUUIDなどの情報を取得して、本当に情報を取得したい機器の詳細情報を見てみたいと思います


※もう少し詳しくコードを知りたい方は、Android SDKの中にあるsamplesに参考となるコードがありますので、そちらを参照ください
samples/android-18/legacy/BluetoothLeGatt/src/com/example/bluetooth/le

2014年5月28日水曜日

AndroidのFused Locationでの精度調査

仕事の関係で調査が必要でしたので、AndroidのFused LocationにてGPS、Wi-Fi、携帯ネットワークを使った場合に精度がどのようになるのか検証してみました

以下の条件での検証です
  • Priorityは「LocationRequest.PRIORITY_HIGH_ACCURACY」
  • permissionは「android.permission.ACCESS_FINE_LOCATION」
  • 仕事場近くの道端にて同じ場所に留まった状態で計測
  • Wi-Fiにはe-mobileのPocket Wi-Fi(GL06P)を使用
  • 携帯回線はDocomo
  • 計測は、それぞれの条件で7回(画像の2枚めの前半は重複した情報です)

GPS + Wi-Fi + 携帯ネットワーク


精度は25m~63mくらいでした

複数のプロバイダーを利用しているのでgetProviderの値が[fused]になるのかと思っていましたが、あとの携帯ネットワークだけの時も同じ値となります。そのためFused Locationの場合getProviderは常に[fused]を返すようですね




GPS + 携帯ネットワーク


次はGPS + 携帯ネットワークです
33m~50mと、最初の Wi-Fiも利用したときとあまり変わりませんね
Wi-Fiは精度に影響がなく、携帯ネットワークがあれば、そこそこ精度が出るのかもしれません




 Wi-Fi + 携帯ネットワーク

次に検証したのがWi-Fi + 携帯ネットワークです

精度は60m以上の精度で上の2つと比較すると精度は良くないですが、利用用途によっては十分に利用可能と思います





携帯ネットワークのみ


最後は携帯ネットワークのみの結果です
このデータだけ計測しながら移動しています
最初の3件目のデータまでは、その場所に留まっていたのですが、4件目は仕事場に向かって歩いています
そして、5件目のデータで仕事場のマンションの通路に入った所で精度が一気に悪くなりました
3km近い誤差が出ています
その後、仕事場の部屋に戻ると精度が33mになっているので、場所によって大きく誤差がでるようですね
誤差が大きくでた場所はGPSも反応しない場所なので、この場所で精度を出すのは現状では難しいと思われます




まとめ


以上の結果からは、Fused Locationを使った計測は精度が高いように思われます
今回の検証ではデータが少なすぎて答えは出せませんが、精度を判定して大きな誤差が出そうなデータは捨てていけば、それなりに高い精度で位置測定できそうです
しかし、状況によっては数kmの誤差もありえます

精度は良くても20mくらい。状況によっては精度がもう少し良くなるかもしれませんがピンポイントでの位置特定に利用することは出来ませんね
ピンポイントでの位置特定にはBeaconや音波などなど他の技術と組み合わせて精度を高めることで実現できるかもしれませんが、それはまた別の機会に調査してみたいと思います

以上、せっかく調査してみたのでブログに記事としてまとめてみました

2014年5月12日月曜日

Remote TestKit Webを試してみた

以前(Remote TestKitで実機の動作テスト)で紹介したRemote TestKitがブラウザだけで利用できるようになったので実際に試してみました

まず、ログインすると端末の選択画面がでてきます
専用ソフトの時とだいたいおんなじ感じですね




さっそく、無料でレンタルできる端末の中から「Samsung Galaxy S4」をレンタルしてみます
一覧の右端にある[レンタル]というボタンを押すと、確認ダイアログが表示されます
ダイアログにある[レンタル]を押すとすぐにブラウザ上に端末の動作画面がでてきます




リモート端末にアプリをインストールするには、画面右のメニューから[ファイルを選択]でapkファイルを選択して、[アプリをインストール]のボタンを実行するだけです

今回はApiDemos.apkをインストールして動かしてみました

1.9MBほどあるApiDemos.apkのインストールが完了して動作するまで20秒くらいで、思っていた以上に素早くインストールできました

ドラッグや選択などの動作はリモートなのでそこそこの遅延はあります
試しにApiDemoにあるOpenGL ESのサンプルを動かしてみましたが、少し遅いかな?と感じますが問題なく動作しました




ブラウザを使ってWebサイトを閲覧することもできるのでスマートフォン用のHTML検証にも使えそうです


試しに自分のところのホームページを表示させてみました


これまで専用ソフトをインストールして利用する必要がありましたが、これからはブラウザだけで手軽に複数端末でのテストが行えるのは非常に助かります

スマートフォンのアプリやサイトを開発をされている方はぜひチェックしてみてください!

ちなみに、iPhoneもレンタル可能です


■Remote TestKit Web Browser Version
https://webapp.appkitbox.com/

■Remote TestKit
http://appkitbox.com/testkit/

2014年4月21日月曜日

ThemeをDialogにしてDialogっぽくしたActivityで枠外をタップした際に画面を閉じるには次のような処理を追加すれば良い

@Override  
public boolean dispatchTouchEvent(MotionEvent event) {  
    Rect dialogRect = new Rect();  
    getWindow().getDecorView().getHitRect(dialogRect);  
  
    if (dialogRect.contains((int) event.getX(), (int) event.getY()) == false) {  
        finish();  
    }  
    return super.dispatchTouchEvent(event);  
}  

2014年1月20日月曜日

今日、打ちあわせの際にMS Officeのファイルを見る必要があったんだけど、Nexu7に入れてあったQuickOfficeでは遅くて表示ができないということがありました


そんな時に今回紹介するAndrOpen Officeを教えてもらったので、紹介しようと思います

AndrOpen OfficeはAndroidで利用できるOpen Officeで、パソコンで使うOpenOfficeと同じような表示になっています
Open Officeを使ったことが無い方はOffice 2003みたいな見た目と思ってください
(下に画像を載せています)

パソコンと同じような画面なので、すごくメニューとか操作するボタンが小さいです
最初は画面をタッチすることで操作しようとしていて「使い難いな」と思っていたのですが、操作メニューを出すと非常に使いやすくなりました



操作メニューは画面右下にあるディスプレイのマークを押す表示されます




今回は見るだけの利用だったので、編集とかの操作性についてはわかりませんが、表示だけならかなり良さそうです

※右クリックで表示されるメニューは画面を長押しする表示されます

利用できるのは
・文書ドキュメント
・表計算ドキュメント
・プレゼンテーション
・図形描画
・データベース
・数式
となっています

メニューバーとかのサイズが小さいのですが、これは変更することができないようです(たぶん)


設定としては出来るのは以下の3つだけです
・倍率(Default:100%)
・カスタムフォント(Default:設定なし)
・フレームレート(Default:5fps)

表示がカクカクする場合はフレームレートを上げると良いと思います

万能で安定している。と、いう訳ではないですがMS Officeを表示しないとマズイ場面になった時にでも思い出してみてください




Cover art


AndrOpen Office(andropenoffice.com)

無料

https://play.google.com/store/apps/developer?id=andropenoffice.com&hl=ja