• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.media;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.concurrent.Callable;
22 
23 import android.app.Service;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.media.session.MediaController;
27 import android.media.session.MediaSession;
28 import android.media.session.MediaSessionManager;
29 import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
30 import android.media.session.PlaybackState;
31 import android.media.session.MediaSession.Callback;
32 import android.view.KeyEvent;
33 
34 import com.googlecode.android_scripting.Log;
35 import com.googlecode.android_scripting.MainThread;
36 import com.googlecode.android_scripting.facade.EventFacade;
37 import com.googlecode.android_scripting.facade.FacadeManager;
38 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
39 import com.googlecode.android_scripting.rpc.Rpc;
40 import com.googlecode.android_scripting.rpc.RpcDefault;
41 import com.googlecode.android_scripting.rpc.RpcParameter;
42 
43 /**
44  * Expose functionalities of MediaSession related classes
45  * like MediaSession, MediaSessionManager, MediaController.
46  *
47  */
48 public class MediaSessionFacade extends RpcReceiver {
49 
50     private final Service mService;
51     private final EventFacade mEventFacade;
52     private final MediaSession mSession;
53     private final MediaSessionManager mManager;
54     private final OnActiveSessionsChangedListener mSessionListener;
55     private final Callback mCallback;
56 
57     private List<MediaController> mActiveControllers = null;
58 
MediaSessionFacade(FacadeManager manager)59     public MediaSessionFacade(FacadeManager manager) {
60         super(manager);
61         mService = manager.getService();
62         mEventFacade = manager.getReceiver(EventFacade.class);
63         Log.d("Creating MediaSession.");
64         mSession = new MediaSession(mService, "SL4A");
65         mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
66         mManager = (MediaSessionManager) mService.getSystemService(Context.MEDIA_SESSION_SERVICE);
67         mCallback = new MediaButtonCallback(mEventFacade);
68         mSessionListener = new MediaSessionListener();
69         mManager.addOnActiveSessionsChangedListener(mSessionListener,
70                 new ComponentName(mService.getPackageName(), this.getClass().getName()));
71         mSession.setActive(true);
72     }
73 
74     private class MediaSessionListener implements OnActiveSessionsChangedListener {
75 
76         @Override
onActiveSessionsChanged(List<MediaController> controllers)77         public void onActiveSessionsChanged(List<MediaController> controllers) {
78             Log.d("Active MediaSessions have changed. Update current controller.");
79             int size = controllers.size();
80             for (int i = 0; i < size; i++) {
81                 MediaController controller = controllers.get(i);
82                 long flags = controller.getFlags();
83                 // We only care about sessions that handle transport controls,
84                 // which will be true for apps using RCC
85                 if ((flags & MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
86                     Log.d("The current active MediaSessions is " + controller.getTag());
87                     return;
88                 }
89             }
90         }
91     }
92 
93     @Rpc(description = "Retrieve a list of active sessions.")
mediaGetActiveSessions()94     public List<String> mediaGetActiveSessions() {
95         mActiveControllers = mManager.getActiveSessions(null);
96         List<String> results = new ArrayList<String>();
97         for (MediaController mc : mActiveControllers) {
98             results.add(mc.getTag());
99         }
100         return results;
101     }
102 
103     @Rpc(description = "Add callback to media session.")
mediaSessionAddCallback()104     public void mediaSessionAddCallback() {
105         MainThread.run(mService, new Callable<Object>() {
106             @Override
107             public Object call() throws Exception {
108                 Log.d("Adding callback.");
109                 mSession.setCallback(mCallback);
110                 PlaybackState.Builder bob = new PlaybackState.Builder();
111                 bob.setActions(PlaybackState.ACTION_PLAY |
112                                PlaybackState.ACTION_PAUSE |
113                                PlaybackState.ACTION_STOP);
114                 bob.setState(PlaybackState.STATE_PLAYING, 0, 1);
115                 mSession.setPlaybackState(bob.build());
116                 return null;
117             }
118         });
119     }
120 
121     @Rpc(description = "Whether current media session is active.")
mediaSessionIsActive()122     public Boolean mediaSessionIsActive() {
123         return mSession.isActive();
124     }
125 
126     @Rpc(description = "Simulate a media key press.")
mediaDispatchMediaKeyEvent(String key)127     public void mediaDispatchMediaKeyEvent(String key) {
128         int keyCode;
129         if (key.equals("Play")) {
130             keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
131         } else if (key.equals("Pause")) {
132             keyCode = KeyEvent.KEYCODE_MEDIA_PAUSE;
133         } else if (key.equals("Stop")) {
134             keyCode = KeyEvent.KEYCODE_MEDIA_STOP;
135         } else if (key.equals("Next")) {
136             keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
137         } else if (key.equals("Previous")) {
138             keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
139         } else if (key.equals("Forward")) {
140             keyCode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
141         } else if (key.equals("Rewind")) {
142             keyCode = KeyEvent.KEYCODE_MEDIA_REWIND;
143         } else {
144             Log.d("Unrecognized media key.");
145             return;
146         }
147         KeyEvent keyDown = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
148         KeyEvent keyUp = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
149         mManager.dispatchMediaKeyEvent(keyDown);
150         mManager.dispatchMediaKeyEvent(keyUp);
151     }
152 
getMediaController(int idx)153     private MediaController getMediaController(int idx) {
154         return mActiveControllers.get(idx);
155     }
156 
157     @Rpc(description = "Call Play on the currently active media session.")
mediaSessionPlay(@pcParametername = "index") @pcDefaultvalue = "0") Integer idx)158     public void mediaSessionPlay(@RpcParameter(name = "index") @RpcDefault(value = "0")
159                                  Integer idx) {
160         getMediaController(idx).getTransportControls().play();
161     }
162 
163     @Rpc(description = "Call Pause on the currently active media session.")
mediaSessionPause(@pcParametername = "index") @pcDefaultvalue = "0") Integer idx)164     public void mediaSessionPause(@RpcParameter(name = "index") @RpcDefault(value = "0")
165                                   Integer idx) {
166         getMediaController(idx).getTransportControls().pause();
167     }
168 
169     @Rpc(description = "Call Stop on the currently active media session.")
mediaSessionStop(@pcParametername = "index") @pcDefaultvalue = "0") Integer idx)170     public void mediaSessionStop(@RpcParameter(name = "index") @RpcDefault(value = "0")
171                                  Integer idx) {
172         getMediaController(idx).getTransportControls().stop();
173     }
174 
175     @Rpc(description = "Call Next on the currently active media session.")
mediaSessionNext(@pcParametername = "index") @pcDefaultvalue = "0") Integer idx)176     public void mediaSessionNext(@RpcParameter(name = "index") @RpcDefault(value = "0")
177                                  Integer idx) {
178         getMediaController(idx).getTransportControls().skipToNext();
179     }
180 
181     @Override
shutdown()182     public void shutdown() {
183         mSession.setCallback(null);
184         mSession.release();
185     }
186 }
187