2015年8月アーカイブ

Android Wear 1.3 から対話型ウォッチフェイス(Interactive watch faces)を作成するためのAPIが追加されました。

 

公式ブログ(Android Developers)

 

このAPIを使用すると、ウォッチフェイスの画面上で ユーザーがタップした座標を取得できる ため、ユーザーのタップ位置に応じて画面表示を切り替えるなど、ユーザーのタップに連動したウォッチフェイスを作ることができます。

具体的な動作イメージについては、「Pujie Black」というウォッチフェイスの [動画ページ] を確認してみるのがよいでしょう。

なお、この API を使用するには、Android Wear のバージョンが 1.3 以上である必要がありますが、このバージョンを搭載したAndroid Wear エミュレーターイメージは既に公開されているため、実機がなくても確認することができます。

Version.png

 

対話型ウォッチフェイスに対応するには?

1. Wearアプリの起動時にWear端末のバージョンが対話型ウォッチフェイスに対応していることを確認する

 ※ XXXWatchFaceService.Engine を継承したクラスの onCreate() で行い、フラグなどで覚えておく

try {
    PackageManager pm = getPackageManager();
    PackageInfo packageInfo = pm.getPackageInfo("com.google.android.wearable.app", 0);
    if (packageInfo.versionCode > 720000000) {
        // 対話型ウオッチフェイスAPI(タップイベントの応答)に対応
    } else {
        // 対話型ウオッチフェイスAPI(タップイベントの応答)に非対応
    }
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

ちなみに versionCode の判定に使用している 720000000 (=Android Wear 1.3)については、定数がないようで困ったものです。

以下、わかる範囲で調べた過去の Android Wear バージョンと versionCode の紐付けです。

  • 1.0.1.1379611 → 201379611
  • 1.0.2.1476973 → 201476973
  • 1.0.4.1580939 → 401580939
  • 1.0.5.1630507 → 501630507 (Android 5.0.2)
  • 1.1.1.1944630 → 701944630 (Android 5.1.1)
  • 1.3.0.2139573 → 722395730 (Android 5.1.1)

 

2. ウオッチフェイススタイルにタップイベントを許可する設定を追加する

 ※ XXXWatchFaceService.Engine を継承したクラスの onCreate() で行う

setWatchFaceStyle(new WatchFaceStyle.Builder(MyWatchFace.this)
    .setAcceptsTapEvents(true) // <---------- この行を追加
    .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
    .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
    .setShowSystemUiTime(false)
    .build());

 

3. タップ時に呼び出される onTapCommand() をオーバーライドし、ユーザーのタップ位置に応じた処理を行う

引数の tapType は、タップ時に TAP_TYPE_TOUCH(0)、離すと TAP_TYPE_TAP(2) がセットされます。

 ※ TAP_TYPE_TOUCH_CANCEL(1) は、長押し時に TAP_TYPE_TOUCH(0) の後に呼び出されていました

@Override
public void onTapCommand(int tapType, int x, int y, long eventTime) {
    super.onTapCommand(tapType, x, y, eventTime);

    // 動作確認用ログ出力
    Log.d(TAG, "onTapCommand(" +
            String.valueOf(tapType) + ":" +
            String.valueOf(x) + "," +
            String.valueOf(y) + ")");
}

 

上記のように、既存のウォッチフェイスのコードに対して、少しのコードを追加するだけで、タップに応答することができます。

タップに応じて、どのような処理をするかは、あなたのアプリケーション次第ですが、これまでよりも機能や表現力が高いウォッチフェイスを作る事ができるため、非常に嬉しいAPIだと思います。

 

Android Developers のサイトには、対話型ウォッチフェイスのパターン例が紹介されていますので、確認してみてください。

android_developers_design.png

出典:https://developer.android.com/design/wear/watchfaces.html#interactive

Android 6.0(Mashmallow)API Level 23から、MIDI機器を制御できるAPIが追加されたので試してみました。

 

■ 準備するもの

  • Android SDKとAndroid StudioをインストールしたPC
  • Android 6.0をインストールした端末
  • USB接続可能なMIDI機器
  • Android端末とMIDI機器を接続するUSBケーブル(USB B-A + A-microB など)

 

必要なものが準備できたら、以下の手順でAndroid端末とMIDI機器をセットアップします。
接続の順番を間違えると、WiFi越しのadb接続が切れたり、MIDI側がAndroid端末を認識しなかったりする可能性があります。

 

■ Android端末をセットアップする

  • あらかじめPC上でAndroid Studioを起動しておく(あとでadbがrestartされないように)
  • Android端末とPCをUSBでつなぎ(通常どおりMTP)接続する
  • Android端末をWiFiネットワークに接続する
  • 「adb tcpip 5555」「adb connect IPアドレス:5555」でWiFi下でadbを使用できるようにする
  • 「adb device」でWiFiのIPに接続された事を確認する
  • Android端末とPC間のUSBケーブルを外す(いったんadbは切れる)

 

■ MIDI機器をセットアップする

  • MIDI機器の電源をオンし、起動時の入力をUSBにして動作するように設定して電源オフ
  • Android端末上で開発者向けオプションなどから「USB設定の選択=MIDI」に切り替える
  • Android端末とMIDI機器をUSB接続してから、MIDI機器の電源をオン
  • 再度「adb connect IPアドレス:5555」でWiFi経由で再接続する

 

セットアップ後は、Android Studio上で適当なプロジェクトを作成し、
以下の解説を参考に、MIDI機器を制御するアプリを作成します。
なお、minSdkVersionは23で作成してください。

 

■ MIDI APIを使用するには?

AndroidManifest.xmlへ以下を追加します。

<uses-feature android:name="android.software.midi" android:required="true"/>

 

■ MIDI機器の情報を取得するには?

システムサービスからMidiManagerを取得後、MidiManager#getDevices()を呼び出すと、
Android端末に接続されているMIDI機器の情報が、MidiDeviceInfoとして取得できます。
MidiDeviceInfoは、MidiDeviceInfo#getProperties()を呼び出すことで、 各種プロパティー情報にアクセスできます。

MidiManager midiManager = (MidiManager)getSystemService(Context.MIDI_SERVICE);
MidiDeviceInfo[] infos = midiManager.getDevices();
if (infos.length > 0)
{
    MidiDeviceInfo info = infos[0]; // 説明用に先頭の情報のみアクセスしてます

    Bundle prop = info.getProperties();

    // 製造元文字列("Roland"など)
    String manufacturer = prop.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);

    // 製品名文字列("EDIROL SD-90"など)
    String product = prop.getString(MidiDeviceInfo.PROPERTY_PRODUCT);

    // 機器名文字列("Roland EDIROL SD-90"など)
    String name = prop.getString(MidiDeviceInfo.PROPERTY_NAME);

    // バージョン文字列("1.16"など)
    String version = prop.getString(MidiDeviceInfo.PROPERTY_VERSION);

    // MIDI機器とUSB接続している場合のみインスタンスが取得できる
    UsbDevice usbDevice = (UsbDevice) prop.get(MidiDeviceInfo.PROPERTY_USB_DEVICE);

    // MIDI機器とBluetooth接続している場合のみインスタンスが取得できる
    BluetoothDevice btDevice = (BluetoothDevice) prop.get(MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE);

    // 入力ポート数(4など)
    int numInputs = info.getInputPortCount();

    // 出力ポート数(4など)
    int numOutputs = info.getOutputPortCount();
}

 

■ MIDI機器の接続/切断/状態変化を知るには?

MidiManager#registerDeviceCallback()を呼び出し、MidiManager.DeviceCallbackインスタンスを登録することで、各種コールバックを受け取ることができます。

midiManager.registerDeviceCallback(new MidiManager.DeviceCallback() {
    @Override
    public void onDeviceAdded(MidiDeviceInfo device) {
        super.onDeviceAdded(device);
        // デバイスが接続された時に呼び出される
        Toast.makeText(MainActivity.this, "onDeviceAdded()", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDeviceRemoved(MidiDeviceInfo device) {
        super.onDeviceRemoved(device);
        // デバイスが切断された時に呼び出される
        Toast.makeText(MainActivity.this, "onDeviceRemoved()", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDeviceStatusChanged(MidiDeviceStatus status) {
        super.onDeviceStatusChanged(status);
        // デバイスが状態が変化した時に呼び出される
        Toast.makeText(MainActivity.this, "onDeviceStatusChanged()", Toast.LENGTH_SHORT).show();
    }
}, new Handler(Looper.getMainLooper())); // 第2引数

 

■ MIDI機器をオープンするには?

MidiManager#openDevice()を呼び出します。
第1引数には、上述したgetDevices()で取得した1つ分のMidiDeviceInfoをセットし、
第2引数には、MidiManager.OnDeviceOpenedListenerインスタンスをセットします。

midiManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() {
    @Override
    public void onDeviceOpened(MidiDevice device) {
        if (device == null) {
            // オープン失敗
        } else {
            // オープン成功
            // ...引数として渡された device インスタンスを使用してMIDI機器を制御する...
        }
    }
}
, new Handler(Looper.getMainLooper())); // 第3引数

 

■ MIDIメッセージを送るには?

オープンして取得したMidiDeviceインスタンスから入力ポートを取得後、
入力ポートに対してMIDIメッセージ(バイト配列)を送信します。
以下の例では、MIDI機器から「ぽーん♩」という感じの音が鳴なります。

MidiInputPort inputPort = device.openInputPort(0);
byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 3; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)60; // pitch is middle C
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;
try {
    inputPort.send(buffer, offset, numBytes);
} catch (IOException e) {
    e.printStackTrace();
}

 

ここまでで、Android端末とMIDI機器を接続し、MIDI機器を制御することができました。
さらなる情報は、公式サイトから得られますので、参考にしてみてください。

http://developer.android.com/reference/android/media/midi/package-summary.html

1

2016年8月

  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31