• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.tv;
18 
19 import android.content.Context;
20 import android.graphics.Rect;
21 import android.media.PlaybackParams;
22 import android.net.Uri;
23 import android.os.Bundle;
24 import android.os.IBinder;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.util.Log;
28 import android.view.InputChannel;
29 import android.view.InputEvent;
30 import android.view.InputEventReceiver;
31 import android.view.Surface;
32 
33 import com.android.internal.os.HandlerCaller;
34 import com.android.internal.os.SomeArgs;
35 
36 /**
37  * Implements the internal ITvInputSession interface to convert incoming calls on to it back to
38  * calls on the public TvInputSession interface, scheduling them on the main thread of the process.
39  *
40  * @hide
41  */
42 public class ITvInputSessionWrapper extends ITvInputSession.Stub implements HandlerCaller.Callback {
43     private static final String TAG = "TvInputSessionWrapper";
44 
45     private static final int EXECUTE_MESSAGE_TIMEOUT_SHORT_MILLIS = 50;
46     private static final int EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS = 2000;
47     private static final int EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS = 5 * 1000;
48 
49     private static final int DO_RELEASE = 1;
50     private static final int DO_SET_MAIN = 2;
51     private static final int DO_SET_SURFACE = 3;
52     private static final int DO_DISPATCH_SURFACE_CHANGED = 4;
53     private static final int DO_SET_STREAM_VOLUME = 5;
54     private static final int DO_TUNE = 6;
55     private static final int DO_SET_CAPTION_ENABLED = 7;
56     private static final int DO_SELECT_TRACK = 8;
57     private static final int DO_APP_PRIVATE_COMMAND = 9;
58     private static final int DO_CREATE_OVERLAY_VIEW = 10;
59     private static final int DO_RELAYOUT_OVERLAY_VIEW = 11;
60     private static final int DO_REMOVE_OVERLAY_VIEW = 12;
61     private static final int DO_UNBLOCK_CONTENT = 13;
62     private static final int DO_TIME_SHIFT_PAUSE = 14;
63     private static final int DO_TIME_SHIFT_RESUME = 15;
64     private static final int DO_TIME_SHIFT_SEEK_TO = 16;
65     private static final int DO_TIME_SHIFT_SET_PLAYBACK_PARAMS = 17;
66     private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 18;
67 
68     private final HandlerCaller mCaller;
69 
70     private TvInputService.Session mTvInputSessionImpl;
71     private InputChannel mChannel;
72     private TvInputEventReceiver mReceiver;
73 
ITvInputSessionWrapper(Context context, TvInputService.Session sessionImpl, InputChannel channel)74     public ITvInputSessionWrapper(Context context, TvInputService.Session sessionImpl,
75             InputChannel channel) {
76         mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */);
77         mTvInputSessionImpl = sessionImpl;
78         mChannel = channel;
79         if (channel != null) {
80             mReceiver = new TvInputEventReceiver(channel, context.getMainLooper());
81         }
82     }
83 
84     @Override
executeMessage(Message msg)85     public void executeMessage(Message msg) {
86         if (mTvInputSessionImpl == null) {
87             return;
88         }
89 
90         long startTime = System.currentTimeMillis();
91         switch (msg.what) {
92             case DO_RELEASE: {
93                 mTvInputSessionImpl.release();
94                 mTvInputSessionImpl = null;
95                 if (mReceiver != null) {
96                     mReceiver.dispose();
97                     mReceiver = null;
98                 }
99                 if (mChannel != null) {
100                     mChannel.dispose();
101                     mChannel = null;
102                 }
103                 break;
104             }
105             case DO_SET_MAIN: {
106                 mTvInputSessionImpl.setMain((Boolean) msg.obj);
107                 break;
108             }
109             case DO_SET_SURFACE: {
110                 mTvInputSessionImpl.setSurface((Surface) msg.obj);
111                 break;
112             }
113             case DO_DISPATCH_SURFACE_CHANGED: {
114                 SomeArgs args = (SomeArgs) msg.obj;
115                 mTvInputSessionImpl.dispatchSurfaceChanged(args.argi1, args.argi2, args.argi3);
116                 args.recycle();
117                 break;
118             }
119             case DO_SET_STREAM_VOLUME: {
120                 mTvInputSessionImpl.setStreamVolume((Float) msg.obj);
121                 break;
122             }
123             case DO_TUNE: {
124                 SomeArgs args = (SomeArgs) msg.obj;
125                 mTvInputSessionImpl.tune((Uri) args.arg1, (Bundle) args.arg2);
126                 args.recycle();
127                 break;
128             }
129             case DO_SET_CAPTION_ENABLED: {
130                 mTvInputSessionImpl.setCaptionEnabled((Boolean) msg.obj);
131                 break;
132             }
133             case DO_SELECT_TRACK: {
134                 SomeArgs args = (SomeArgs) msg.obj;
135                 mTvInputSessionImpl.selectTrack((Integer) args.arg1, (String) args.arg2);
136                 args.recycle();
137                 break;
138             }
139             case DO_APP_PRIVATE_COMMAND: {
140                 SomeArgs args = (SomeArgs) msg.obj;
141                 mTvInputSessionImpl.appPrivateCommand((String) args.arg1, (Bundle) args.arg2);
142                 args.recycle();
143                 break;
144             }
145             case DO_CREATE_OVERLAY_VIEW: {
146                 SomeArgs args = (SomeArgs) msg.obj;
147                 mTvInputSessionImpl.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
148                 args.recycle();
149                 break;
150             }
151             case DO_RELAYOUT_OVERLAY_VIEW: {
152                 mTvInputSessionImpl.relayoutOverlayView((Rect) msg.obj);
153                 break;
154             }
155             case DO_REMOVE_OVERLAY_VIEW: {
156                 mTvInputSessionImpl.removeOverlayView(true);
157                 break;
158             }
159             case DO_UNBLOCK_CONTENT: {
160                 mTvInputSessionImpl.unblockContent((String) msg.obj);
161                 break;
162             }
163             case DO_TIME_SHIFT_PAUSE: {
164                 mTvInputSessionImpl.timeShiftPause();
165                 break;
166             }
167             case DO_TIME_SHIFT_RESUME: {
168                 mTvInputSessionImpl.timeShiftResume();
169                 break;
170             }
171             case DO_TIME_SHIFT_SEEK_TO: {
172                 mTvInputSessionImpl.timeShiftSeekTo((Long) msg.obj);
173                 break;
174             }
175             case DO_TIME_SHIFT_SET_PLAYBACK_PARAMS: {
176                 mTvInputSessionImpl.timeShiftSetPlaybackParams((PlaybackParams) msg.obj);
177                 break;
178             }
179             case DO_TIME_SHIFT_ENABLE_POSITION_TRACKING: {
180                 mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
181                 break;
182             }
183             default: {
184                 Log.w(TAG, "Unhandled message code: " + msg.what);
185                 break;
186             }
187         }
188         long duration = System.currentTimeMillis() - startTime;
189         if (duration > EXECUTE_MESSAGE_TIMEOUT_SHORT_MILLIS) {
190             Log.w(TAG, "Handling message (" + msg.what + ") took too long time (duration="
191                     + duration + "ms)");
192             if (msg.what == DO_TUNE && duration > EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS) {
193                 throw new RuntimeException("Too much time to handle tune request. (" + duration
194                         + "ms > " + EXECUTE_MESSAGE_TUNE_TIMEOUT_MILLIS + "ms) "
195                         + "Consider handling the tune request in a separate thread.");
196             }
197             if (duration > EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS) {
198                 throw new RuntimeException("Too much time to handle a request. (type=" + msg.what +
199                         ", " + duration + "ms > " + EXECUTE_MESSAGE_TIMEOUT_LONG_MILLIS + "ms).");
200             }
201         }
202     }
203 
204     @Override
release()205     public void release() {
206         mTvInputSessionImpl.scheduleOverlayViewCleanup();
207         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
208     }
209 
210     @Override
setMain(boolean isMain)211     public void setMain(boolean isMain) {
212         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_MAIN, isMain));
213     }
214 
215     @Override
setSurface(Surface surface)216     public void setSurface(Surface surface) {
217         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_SURFACE, surface));
218     }
219 
220     @Override
dispatchSurfaceChanged(int format, int width, int height)221     public void dispatchSurfaceChanged(int format, int width, int height) {
222         mCaller.executeOrSendMessage(mCaller.obtainMessageIIII(DO_DISPATCH_SURFACE_CHANGED,
223                 format, width, height, 0));
224     }
225 
226     @Override
setVolume(float volume)227     public final void setVolume(float volume) {
228         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_STREAM_VOLUME, volume));
229     }
230 
231     @Override
tune(Uri channelUri, Bundle params)232     public void tune(Uri channelUri, Bundle params) {
233         // Clear the pending tune requests.
234         mCaller.removeMessages(DO_TUNE);
235         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_TUNE, channelUri, params));
236     }
237 
238     @Override
setCaptionEnabled(boolean enabled)239     public void setCaptionEnabled(boolean enabled) {
240         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_CAPTION_ENABLED, enabled));
241     }
242 
243     @Override
selectTrack(int type, String trackId)244     public void selectTrack(int type, String trackId) {
245         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_SELECT_TRACK, type, trackId));
246     }
247 
248     @Override
appPrivateCommand(String action, Bundle data)249     public void appPrivateCommand(String action, Bundle data) {
250         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action,
251                 data));
252     }
253 
254     @Override
createOverlayView(IBinder windowToken, Rect frame)255     public void createOverlayView(IBinder windowToken, Rect frame) {
256         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_OVERLAY_VIEW, windowToken,
257                 frame));
258     }
259 
260     @Override
relayoutOverlayView(Rect frame)261     public void relayoutOverlayView(Rect frame) {
262         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RELAYOUT_OVERLAY_VIEW, frame));
263     }
264 
265     @Override
removeOverlayView()266     public void removeOverlayView() {
267         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW));
268     }
269 
270     @Override
unblockContent(String unblockedRating)271     public void unblockContent(String unblockedRating) {
272         mCaller.executeOrSendMessage(mCaller.obtainMessageO(
273                 DO_UNBLOCK_CONTENT, unblockedRating));
274     }
275 
276     @Override
timeShiftPause()277     public void timeShiftPause() {
278         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_TIME_SHIFT_PAUSE));
279     }
280 
281     @Override
timeShiftResume()282     public void timeShiftResume() {
283         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_TIME_SHIFT_RESUME));
284     }
285 
286     @Override
timeShiftSeekTo(long timeMs)287     public void timeShiftSeekTo(long timeMs) {
288         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TIME_SHIFT_SEEK_TO, timeMs));
289     }
290 
291     @Override
timeShiftSetPlaybackParams(PlaybackParams params)292     public void timeShiftSetPlaybackParams(PlaybackParams params) {
293         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TIME_SHIFT_SET_PLAYBACK_PARAMS,
294                 params));
295     }
296 
297     @Override
timeShiftEnablePositionTracking(boolean enable)298     public void timeShiftEnablePositionTracking(boolean enable) {
299         mCaller.executeOrSendMessage(mCaller.obtainMessageO(
300                 DO_TIME_SHIFT_ENABLE_POSITION_TRACKING, enable));
301     }
302 
303     private final class TvInputEventReceiver extends InputEventReceiver {
TvInputEventReceiver(InputChannel inputChannel, Looper looper)304         public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
305             super(inputChannel, looper);
306         }
307 
308         @Override
onInputEvent(InputEvent event)309         public void onInputEvent(InputEvent event) {
310             if (mTvInputSessionImpl == null) {
311                 // The session has been finished.
312                 finishInputEvent(event, false);
313                 return;
314             }
315 
316             int handled = mTvInputSessionImpl.dispatchInputEvent(event, this);
317             if (handled != TvInputManager.Session.DISPATCH_IN_PROGRESS) {
318                 finishInputEvent(event, handled == TvInputManager.Session.DISPATCH_HANDLED);
319             }
320         }
321     }
322 }
323