3 ** Copyright 2013, The Android Open Source Project
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 package com
.android
.commands
.media
;
20 import android
.app
.ActivityManager
;
21 import android
.content
.Context
;
22 import android
.content
.pm
.ParceledListSlice
;
23 import android
.media
.MediaMetadata
;
24 import android
.media
.session
.ISessionController
;
25 import android
.media
.session
.ISessionControllerCallback
;
26 import android
.media
.session
.ISessionManager
;
27 import android
.media
.session
.ParcelableVolumeInfo
;
28 import android
.media
.session
.PlaybackState
;
29 import android
.os
.Bundle
;
30 import android
.os
.HandlerThread
;
31 import android
.os
.IBinder
;
32 import android
.os
.RemoteException
;
33 import android
.os
.ServiceManager
;
34 import android
.os
.SystemClock
;
35 import android
.util
.AndroidException
;
36 import android
.view
.InputDevice
;
37 import android
.view
.KeyCharacterMap
;
38 import android
.view
.KeyEvent
;
40 import com
.android
.internal
.os
.BaseCommand
;
42 import java
.io
.BufferedReader
;
43 import java
.io
.IOException
;
44 import java
.io
.InputStreamReader
;
45 import java
.io
.PrintStream
;
46 import java
.util
.List
;
48 public class Media
extends BaseCommand
{
49 private ISessionManager mSessionService
;
52 * Command-line entry point.
54 * @param args The command-line arguments
56 public static void main(String
[] args
) {
57 (new Media()).run(args
);
60 public void onShowUsage(PrintStream out
) {
62 "usage: media [subcommand] [options]\n" +
63 " media dispatch KEY\n" +
64 " media list-sessions\n" +
65 " media monitor <tag>\n" +
67 "media dispatch: dispatch a media key to the system.\n" +
68 " KEY may be: play, pause, play-pause, mute, headsethook,\n" +
69 " stop, next, previous, rewind, record, fast-forword.\n" +
70 "media list-sessions: print a list of the current sessions.\n" +
71 "media monitor: monitor updates to the specified session.\n" +
72 " Use the tag from list-sessions.\n"
76 public void onRun() throws Exception
{
77 mSessionService
= ISessionManager
.Stub
.asInterface(ServiceManager
.checkService(
78 Context
.MEDIA_SESSION_SERVICE
));
79 if (mSessionService
== null) {
80 System
.err
.println(NO_SYSTEM_ERROR_CODE
);
81 throw new AndroidException(
82 "Can't connect to media session service; is the system running?");
85 String op
= nextArgRequired();
87 if (op
.equals("dispatch")) {
89 } else if (op
.equals("list-sessions")) {
91 } else if (op
.equals("monitor")) {
94 showError("Error: unknown command '" + op
+ "'");
99 private void sendMediaKey(KeyEvent event
) {
101 mSessionService
.dispatchMediaKeyEvent(event
, false);
102 } catch (RemoteException e
) {
106 private void runMonitor() throws Exception
{
107 String id
= nextArgRequired();
109 showError("Error: must include a session id");
112 boolean success
= false;
114 List
<IBinder
> sessions
= mSessionService
115 .getSessions(null, ActivityManager
.getCurrentUser());
116 for (IBinder session
: sessions
) {
117 ISessionController controller
= ISessionController
.Stub
.asInterface(session
);
119 if (controller
!= null && id
.equals(controller
.getTag())) {
120 ControllerMonitor monitor
= new ControllerMonitor(controller
);
125 } catch (RemoteException e
) {
129 } catch (Exception e
) {
130 System
.out
.println("***Error monitoring session*** " + e
.getMessage());
133 System
.out
.println("No session found with id " + id
);
137 private void runDispatch() throws Exception
{
138 String cmd
= nextArgRequired();
140 if ("play".equals(cmd
)) {
141 keycode
= KeyEvent
.KEYCODE_MEDIA_PLAY
;
142 } else if ("pause".equals(cmd
)) {
143 keycode
= KeyEvent
.KEYCODE_MEDIA_PAUSE
;
144 } else if ("play-pause".equals(cmd
)) {
145 keycode
= KeyEvent
.KEYCODE_MEDIA_PLAY_PAUSE
;
146 } else if ("mute".equals(cmd
)) {
147 keycode
= KeyEvent
.KEYCODE_MUTE
;
148 } else if ("headsethook".equals(cmd
)) {
149 keycode
= KeyEvent
.KEYCODE_HEADSETHOOK
;
150 } else if ("stop".equals(cmd
)) {
151 keycode
= KeyEvent
.KEYCODE_MEDIA_STOP
;
152 } else if ("next".equals(cmd
)) {
153 keycode
= KeyEvent
.KEYCODE_MEDIA_NEXT
;
154 } else if ("previous".equals(cmd
)) {
155 keycode
= KeyEvent
.KEYCODE_MEDIA_PREVIOUS
;
156 } else if ("rewind".equals(cmd
)) {
157 keycode
= KeyEvent
.KEYCODE_MEDIA_REWIND
;
158 } else if ("record".equals(cmd
)) {
159 keycode
= KeyEvent
.KEYCODE_MEDIA_RECORD
;
160 } else if ("fast-forward".equals(cmd
)) {
161 keycode
= KeyEvent
.KEYCODE_MEDIA_FAST_FORWARD
;
163 showError("Error: unknown dispatch code '" + cmd
+ "'");
167 final long now
= SystemClock
.uptimeMillis();
168 sendMediaKey(new KeyEvent(now
, now
, KeyEvent
.ACTION_DOWN
, keycode
, 0, 0,
169 KeyCharacterMap
.VIRTUAL_KEYBOARD
, 0, 0, InputDevice
.SOURCE_KEYBOARD
));
170 sendMediaKey(new KeyEvent(now
, now
, KeyEvent
.ACTION_UP
, keycode
, 0, 0,
171 KeyCharacterMap
.VIRTUAL_KEYBOARD
, 0, 0, InputDevice
.SOURCE_KEYBOARD
));
174 class ControllerMonitor
extends ISessionControllerCallback
.Stub
{
175 private final ISessionController mController
;
177 public ControllerMonitor(ISessionController controller
) {
178 mController
= controller
;
182 public void onSessionDestroyed() {
183 System
.out
.println("onSessionDestroyed. Enter q to quit.");
188 public void onEvent(String event
, Bundle extras
) {
189 System
.out
.println("onSessionEvent event=" + event
+ ", extras=" + extras
);
193 public void onPlaybackStateChanged(PlaybackState state
) {
194 System
.out
.println("onPlaybackStateChanged " + state
);
198 public void onMetadataChanged(MediaMetadata metadata
) {
199 String mmString
= metadata
== null ?
null : "title=" + metadata
201 System
.out
.println("onMetadataChanged " + mmString
);
205 public void onQueueChanged(ParceledListSlice queue
) throws RemoteException
{
206 System
.out
.println("onQueueChanged, "
207 + (queue
== null ?
"null queue" : " size=" + queue
.getList().size()));
211 public void onQueueTitleChanged(CharSequence title
) throws RemoteException
{
212 System
.out
.println("onQueueTitleChange " + title
);
216 public void onExtrasChanged(Bundle extras
) throws RemoteException
{
217 System
.out
.println("onExtrasChanged " + extras
);
221 public void onVolumeInfoChanged(ParcelableVolumeInfo info
) throws RemoteException
{
222 System
.out
.println("onVolumeInfoChanged " + info
);
225 void printUsageMessage() {
227 System
.out
.println("V2Monitoring session " + mController
.getTag()
228 + "... available commands: play, pause, next, previous");
229 } catch (RemoteException e
) {
230 System
.out
.println("Error trying to monitor session!");
232 System
.out
.println("(q)uit: finish monitoring");
235 void run() throws RemoteException
{
237 HandlerThread cbThread
= new HandlerThread("MediaCb") {
239 protected void onLooperPrepared() {
241 mController
.registerCallbackListener(ControllerMonitor
.this);
242 } catch (RemoteException e
) {
243 System
.out
.println("Error registering monitor callback");
250 InputStreamReader converter
= new InputStreamReader(System
.in
);
251 BufferedReader in
= new BufferedReader(converter
);
254 while ((line
= in
.readLine()) != null) {
255 boolean addNewline
= true;
256 if (line
.length() <= 0) {
258 } else if ("q".equals(line
) || "quit".equals(line
)) {
260 } else if ("play".equals(line
)) {
262 } else if ("pause".equals(line
)) {
264 } else if ("next".equals(line
)) {
266 } else if ("previous".equals(line
)) {
267 mController
.previous();
269 System
.out
.println("Invalid command: " + line
);
272 synchronized (this) {
274 System
.out
.println("");
279 } catch (IOException e
) {
282 cbThread
.getLooper().quit();
284 mController
.unregisterCallbackListener(this);
285 } catch (Exception e
) {
292 private void runListSessions() {
293 System
.out
.println("Sessions:");
295 List
<IBinder
> sessions
= mSessionService
296 .getSessions(null, ActivityManager
.getCurrentUser());
297 for (IBinder session
: sessions
) {
299 ISessionController controller
= ISessionController
.Stub
.asInterface(session
);
300 if (controller
!= null) {
302 System
.out
.println(" tag=" + controller
.getTag()
303 + ", package=" + controller
.getPackageName());
304 } catch (RemoteException e
) {
309 } catch (Exception e
) {
310 System
.out
.println("***Error listing sessions***");