仙石浩明の日記

2010年7月17日

Nexus One の近接センサ/環境光センサは、どこにあるのか?調べてみた hatena_b

Nexus One など最近のスマートフォンには、 加速度 (Accelerometer)、 環境光 (照度, Ambient Light)、 磁場 (磁界, Magnetic Field)、 方位 (電子コンパス, Orientation)、 近接 (Proximity) など、 様々なセンサがついている。 いろいろ応用できそうで夢がふくらむが、 携帯電話本来の使い方 (つまり通話すること) において、 使い勝手に直接影響する重要なセンサが近接センサ。

Nexus One や iPhone など全面タッチパネルの携帯電話だと、 (受話器として使うために) 耳に近づけたときタッチパネルが反応しては困る。 そこで近接センサを使って顔が接近してくることを感知し、 タッチパネルを無効にする (ついでにディスプレイをオフにして消費電力を抑える)。

私は Proximity なんて聞くと、 Proximity Warning System (接近警報システム) を思い浮かべてしまうくらいで、 携帯電話用の近接センサがどういうしくみか全く知らなかった。 今年1月の Nexus One の発表の時に近接センサのことを初めて知り、 その時はタッチパネル全体への接近を感知する (静電容量の変化を検知して?) のかと想像したが、 後述するように Nexus One の近接センサはタッチパネルの左上にしかなく、 タッチパネルの下方への接近は感知できないことが分かった。

Nexus One のどこに近接センサが搭載されているか、 センサの感応範囲がどれくらいなのか、 私には見当もつかなかったし、 google で検索してもその手の情報は見つからなかったので、 近接センサが感知した値を表示するだけの簡単なプログラムを書いてみた。

実は、 私にとって初めての android アプリ (^^;)。 しかも、 ここ数年 Java から遠ざかっていたので、 久々に書く Java プログラムだったりする。

お膳立ては Android SDK が全てやってくれるので、 わずか 74行のプログラム。 まず SensorManager#getSensorList メソッドで、 PROXIMITY タイプのセンサを取得し (sensor)、

        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        List<Sensor> sensors
            = sensorManager.getSensorList(Sensor.TYPE_PROXIMITY);
        Sensor sensor = sensors.get(0);

この sensor の値が変化したときなどにセンサの値を受け取るリスナ (SensorEventListener) を、 SensorManager#registerListener メソッドで登録するだけ。

public class Proximity implements SensorEventListener {
        ...
        sensorManager.registerListener(this, sensor,
                                       SensorManager.SENSOR_DELAY_NORMAL);
        ...
    @Override
    public void onSensorChanged(SensorEvent event) {
        view.update(event.values);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}

近接センサの値が変化するとリスナの onSensorChanged メソッドが呼び出されるので、 新しいセンサ値を描画する (view.update):

        void update(float[] values) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas == null) return;
            canvas.drawColor(Color.WHITE);
            Paint paint = new Paint();
            paint.setColor(Color.BLACK);
            paint.setTextSize(40);
            float height = paint.getTextSize();
            for (int i = 0; i < values.length; i++) {
                canvas.drawText(" "+values[i], 0, height * (i + 1), paint);
            }
            getHolder().unlockCanvasAndPost(canvas);
        }

Nexus One のタッチパネル左上隅近く (黒枠部分) にセンサがあるらしく、 パネルまで 2cm ほどの距離に物体を近づけると反応する (センサの値が 9.0 から 0.0 へ変化する)。 また、 パネルと並行に物体を動かす場合、 センサの真上から 1cm ほど外れると反応しなくなる。

Proximity Sensor  ←  鈴を近づけたことにより、
近接センサが反応して、
値が 0.0 になっている

赤外線型の近接センサ (赤外線を照射し、近接する物体からの反射光を測定するセンサ) なので、 凸面の物体など赤外線があさっての方向へ反射してしまって受光素子に正しく届かない場合や、 あるいは黒色の物体などあまり反射しない場合などでは、 より近づけないと反応しない。

例えば、 黒く細い丸棒などだと 1cm 以下に近づけないと反応しない。 逆に白い紙 (凹面〜平面) など、 効果的に赤外線を反射し、かつ受光素子に反射光が効率的に届くケースだと、 2cm より遠くても (8cm くらいでも) 反応する。

ちなみに、 Nexus One に搭載されている近接センサは、 Capella MicrosystemsCM3602 という、 環境光センサ付短距離近接センサ (Short Distance Proximity Sensor with Ambient Light Sensor) であるようだ。 名前の通り環境光も測定できる。 おそらく近接センサの受光素子をそのまま使って照度を測定しているのだろう。

前述したプログラムにおいて、 「Sensor.TYPE_PROXIMITY」 を 「Sensor.TYPE_LIGHT」 に置き換えれば、 環境光センサの値を読み取ることができる。

Android SDK において、 Eclipse を使わずにアプリを開発する方法を説明しているページが少ないので、 蛇足ながらビルド〜インストール方法を書いてみる。 まず android コマンド (Android SDK の tools ディレクトリにある) を使って Project ディレクトリを作る:

T:\src\android>android create project --target 1 --path Proximity --activity Proximity --package org.gcd.test
Created project directory: T:\src\android\Proximity
Created directory T:\src\android\Proximity\src\org\gcd\test
Added file T:\src\android\Proximity\src\org\gcd\test\Proximity.java
Created directory T:\src\android\Proximity\res
Created directory T:\src\android\Proximity\bin
Created directory T:\src\android\Proximity\libs
Created directory T:\src\android\Proximity\res\values
Added file T:\src\android\Proximity\res\values\strings.xml
Created directory T:\src\android\Proximity\res\layout
Added file T:\src\android\Proximity\res\layout\main.xml
Created directory T:\src\android\Proximity\res\drawable-hdpi
Created directory T:\src\android\Proximity\res\drawable-mdpi
Created directory T:\src\android\Proximity\res\drawable-ldpi
Added file T:\src\android\Proximity\AndroidManifest.xml
Added file T:\src\android\Proximity\build.xml

T:\src\android>

「--target <target_ID>」 オプションは、 利用する Android platform library を指定する。 <target_ID> の一覧は、 「android list targets」 を実行することで得られる。

「--activity <activity_name>」 オプションは、 アプリを起動したとき最初に表示される画面のクラス名を指定する。

作った Project ディレクトリ T:\src\android\Proximity の中に、 T:\src\android\Proximity\src\org\gcd\test\Proximity.java があるので、 これを書き換える。 私の場合、 T: ドライブは Linux マシン (正確に言えば coLinux) のファイルシステムなので、 Linux 上の emacs を使って書き換えている。

あとは ant コマンドを使ってビルドするだけ。 Eclipse などの IDE (統合開発環境) を使う必要性を全く感じないのだが...

T:\src\android>cd Proximity

T:\src\android\Proximity>ant debug
Buildfile: T:\src\android\Proximity\build.xml
    [setup] Android SDK Tools Revision 6
    [setup] Project Target: Google APIs
    [setup] Vendor: Google Inc.
    [setup] Platform Version: 2.1-update1
    [setup] API level: 7
    [setup] WARNING: No minSdkVersion value set. Application will install on all Android versions.
    [setup] Importing rules file: platforms\android-7\ant\ant_rules_r2.xml

-compile-tested-if-test:

-dirs:
     [echo] Creating output directories if needed...
    [mkdir] Created dir: T:\src\android\Proximity\gen
    [mkdir] Created dir: T:\src\android\Proximity\bin\classes

-resource-src:
     [echo] Generating R.java / Manifest.java from the resources...

-aidl:
     [echo] Compiling aidl files into Java classes...

compile:
    [javac] C:\android-sdk-windows\platforms\android-7\ant\ant_rules_r2.xml:255: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Warning: org\gcd\test\R.java modified in the future.
    [javac] Compiling 2 source files to T:\src\android\Proximity\bin\classes

-dex:
     [echo] Converting compiled files and external libraries into T:\src\android\Proximity\bin\classes.dex...

-package-resources:
     [echo] Packaging resources
 [aaptexec] Creating full resource package...

-package-debug-sign:
[apkbuilder] Creating Proximity-debug-unaligned.apk and signing it with a debug key...
[apkbuilder] Using keystore: C:\Documents and Settings\sengoku\.android\debug.keystore

debug:
     [echo] Running zip align on final apk...
     [echo] Debug Package: T:\src\android\Proximity\bin\Proximity-debug.apk

BUILD SUCCESSFUL
Total time: 6 seconds
T:\src\android\Proximity>

T:\src\android\Proximity\bin\Proximity-debug.apk に apk ファイル (Android Package) ができるので、 adb コマンド (これも Android SDK の tools ディレクトリにある) を使って Nexus One へインストールする。

T:\src\android\Proximity>adb install bin\Proximity-debug.apk
296 KB/s (14596 bytes in 0.048s)
        pkg: /data/local/tmp/Proximity-debug.apk
Success

T:\src\android\Proximity>

あるいは、 T:\src\android\Proximity\bin\Proximity-debug.apk を Web サーバ上に置いて、 Internet 経由でダウンロード & インストールしてもよい (アプリケーションの設定にて、 「提供元不明のアプリ」 のインストールの許可が必要)。

以上、 Windows のコマンドプロンプトでの実行例を示したが、 もちろん Linux 上でも全く同様にビルド〜インストールが可能。

Filed under: Android,プログラミングと開発環境 — hiroaki_sengoku @ 08:55

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment