Engineer Llfe Dogear

エンジニアリング活動におけるメモやTipsを書くブログ

RemoteControllerの使い方

AndroidKitkat(API level19)で新たに追加されたRemoteControllerというAPIについて少しStudyする機会があったので、そのメモを残します。 日本語だけでなく海外の記事も少なかったのであまり使われていないのだと思います。 今回のメモは以下の記事を元にしています。サンプルコードもgithub上で公開されているので参考になると思います。

[GUIDE] Implement RemoteController in your app - XDA Forum

RemoteControllerとは?

RemoteControllerとは、RemoteControlClientを実装したプレーヤーアプリケーションの再生、ディスプレイ、プレーヤーで再生するコンテンツのメタデータ、再生状態などを制御、更新するための仕組みです。

RemoteControllerをAudioManger#registerRemoteControllerにより、システムに登録することで、現在再生中のRemoteControlClientを実装したプレーヤーアプリ制御することができます。 RemoteControlClientはそもそもロック状態の時に、システムからプレーヤーの再生制御ができるための仕組みだったみたいですが、RemoteControllerの登場により、RemoteControllerからより多くの制御ができるよう、API level19で拡張されたみたいです。

RemoteControllerの実装方法

1. RemoteControllerを利用するめの設定

RemoteControllerを利用して、RemoteControlClientを実装したMedia Playerの制御を行うために、NotificationListenerServiceを継承したServiceを実装します。 NotificationListenerServiceにより、システムのイベントの通知を受け取るためには、 以下のように、android.permission.BIND_NOTIFICATION_LISTENER_SERVICEのpermissionを指定する必要があります。

<service
android:name="<service-package>.<service-name>"
android:label="@string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
    <intent-filter>
       <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>

RemoteControllerの利用するために、必ずしもNotificationListenerServiceを継承したServiceを実装する必要はないのですが、 android.permission.BIND_NOTIFICATION_LISTENER_SERVICEのpermissionは、利用するために必ず指定する必要があるようです。
また、このpermissionを有効にするためには、Androidの設定->セキュリティ->通知へのアクセス->該当アプリケーションにチェックをつける 、ということを手動で行う必要があります。最初、これに気づかずにRemoteControllerが利用できなくて困ってしまいました。 android.permission.BIND_NOTIFICATION_LISTENER_SERVICEを設定したアプリをインストールすると、該当アプリケーションの中にアプリ名が追加されます。

2. RemoteController#OnClientUpdateListener の実装

RemoteControllerのコンストラクタの引数にRemoteController#OnClientUpdateListenerが含まれています。これを実装することで、RemoteControlClientの状態変化などの通知を受け取り、それに応じてRemoteControllerの処理を行うことができます。 RemoteController#OnClientUpdateListenerのメソッドには以下のものがあります。

  • onClientChange(boolean clearing)
    • このListenerの別のメソッドを介して、過去に取得した情報が有効でなくなったり、更新される場合に通知される。
      (RemoteControlClient実装時に、requestAudioFocusでAudioFocusを取得する場合に呼ばれている気がします)
  • onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor)
    • 新しいメタデータが有効になった場合に呼ばれる
      (RemoteControlClinetのeditMetadataにより、メタデータの更新を行ったときに通知を受けているようです。)
  • onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, long currentPosMs, float speed)
    • playback 状態が変更、playback位置やスピードを知らせる場合に呼ばれる
      (RemoteControlClinetのsetPlaybackState(int state, long timeInMs, float playbackSpeed)が呼ばれた時に呼ばれている気がします)
  • onClientPlaybackStateUpdate(int state)
    • playback状態が変更されたときに呼ばれる
      (RemoteControlClientのsetPlaybackState(int state)が呼ばれた時に通知を受けているようです。)
  • onClientTransportControlUpdate(int transportControlFlags)
    • クライアントがサポートするトランスポートフラグ(RemoteContolでどの制御が可能かを指定するフラグ)が変更れた場合に呼ばれる
      (RemoteControlClientのsetTransportControlFlags呼び出し時に、通知を受けているようです。)

3. RemoteControllerの作成と登録

  • RemoteControllerインスタンスを作成
    • 引数に、Contextと手順2で説明をした、OnClinetUpdateListnerを実装したものを指定します。
  • RemoteContollerの登録
    • AudioManagerのregisterRemoteControllerにより、作成したRemotecontrollerインスタンスを指定することで登録

その他

  • RemoteContoller#setSynchronizationModeを呼び出すとexceptionが発生する
    • 上記で挙げた、Remotecontrollerをstudyする元の文献のサンプルコード内にも記述されていますが、setSynchronizationModeがうまく呼び出せません。バグなのか、うまく呼び出すための設定が必要なのか、今のところはわかりません。