1 /* 2 * Copyright 2021 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.interactive; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.content.res.Resources; 24 import android.content.res.XmlResourceParser; 25 import android.graphics.PixelFormat; 26 import android.graphics.Rect; 27 import android.graphics.RectF; 28 import android.media.PlaybackParams; 29 import android.media.tv.TvInputManager; 30 import android.media.tv.TvRecordingInfo; 31 import android.media.tv.TvTrackInfo; 32 import android.media.tv.TvView; 33 import android.media.tv.interactive.TvInteractiveAppManager.Session; 34 import android.media.tv.interactive.TvInteractiveAppManager.Session.FinishedInputEventCallback; 35 import android.media.tv.interactive.TvInteractiveAppManager.SessionCallback; 36 import android.net.Uri; 37 import android.os.Bundle; 38 import android.os.Handler; 39 import android.util.AttributeSet; 40 import android.util.Log; 41 import android.util.Xml; 42 import android.view.InputEvent; 43 import android.view.KeyEvent; 44 import android.view.Surface; 45 import android.view.SurfaceHolder; 46 import android.view.SurfaceView; 47 import android.view.View; 48 import android.view.ViewGroup; 49 import android.view.ViewRootImpl; 50 51 import java.security.KeyStore; 52 import java.util.Arrays; 53 import java.util.List; 54 import java.util.concurrent.Executor; 55 56 /** 57 * Displays contents of interactive TV applications. 58 */ 59 public class TvInteractiveAppView extends ViewGroup { 60 private static final String TAG = "TvInteractiveAppView"; 61 private static final boolean DEBUG = false; 62 63 private static final int SET_TVVIEW_SUCCESS = 1; 64 private static final int SET_TVVIEW_FAIL = 2; 65 private static final int UNSET_TVVIEW_SUCCESS = 3; 66 private static final int UNSET_TVVIEW_FAIL = 4; 67 68 /** 69 * Used to share client {@link java.security.cert.Certificate} with 70 * {@link TvInteractiveAppService}. 71 * @see #createBiInteractiveApp(Uri, Bundle) 72 * @see java.security.cert.Certificate 73 */ 74 public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate"; 75 /** 76 * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}. 77 * @see #createBiInteractiveApp(Uri, Bundle) 78 * @see KeyStore#aliases() 79 */ 80 public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias"; 81 /** 82 * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}. 83 * <p>The private key is optional. It is used to encrypt data when necessary. 84 * 85 * @see #createBiInteractiveApp(Uri, Bundle) 86 * @see java.security.PrivateKey 87 */ 88 public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key"; 89 /** 90 * Additional HTTP headers to be used by {@link TvInteractiveAppService} to load the 91 * broadcast-independent interactive application. 92 * @see #createBiInteractiveApp(Uri, Bundle) 93 */ 94 public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS = 95 "http_additional_headers"; 96 /** 97 * HTTP user agent to be used by {@link TvInteractiveAppService} for broadcast-independent 98 * interactive application. 99 * @see #createBiInteractiveApp(Uri, Bundle) 100 */ 101 public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent"; 102 103 /** 104 * The name of the method where the error happened, if applicable. For example, if there is an 105 * error during signing, the request name is "onRequestSigning". 106 * @see #notifyError(String, Bundle) 107 */ 108 public static final String ERROR_KEY_METHOD_NAME = "method_name"; 109 110 private final TvInteractiveAppManager mTvInteractiveAppManager; 111 private final Handler mHandler = new Handler(); 112 private final Object mCallbackLock = new Object(); 113 private Session mSession; 114 private MySessionCallback mSessionCallback; 115 private TvInteractiveAppCallback mCallback; 116 private Executor mCallbackExecutor; 117 private SurfaceView mSurfaceView; 118 private Surface mSurface; 119 120 private boolean mSurfaceChanged; 121 private int mSurfaceFormat; 122 private int mSurfaceWidth; 123 private int mSurfaceHeight; 124 125 private boolean mUseRequestedSurfaceLayout; 126 private int mSurfaceViewLeft; 127 private int mSurfaceViewRight; 128 private int mSurfaceViewTop; 129 private int mSurfaceViewBottom; 130 131 private boolean mMediaViewCreated; 132 private Rect mMediaViewFrame; 133 134 private final AttributeSet mAttrs; 135 private final int mDefStyleAttr; 136 private final XmlResourceParser mParser; 137 private OnUnhandledInputEventListener mOnUnhandledInputEventListener; 138 139 private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { 140 @Override 141 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 142 if (DEBUG) { 143 Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format 144 + ", width=" + width + ", height=" + height + ")"); 145 } 146 mSurfaceFormat = format; 147 mSurfaceWidth = width; 148 mSurfaceHeight = height; 149 mSurfaceChanged = true; 150 dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight); 151 } 152 153 @Override 154 public void surfaceCreated(SurfaceHolder holder) { 155 mSurface = holder.getSurface(); 156 setSessionSurface(mSurface); 157 } 158 159 @Override 160 public void surfaceDestroyed(SurfaceHolder holder) { 161 mSurface = null; 162 mSurfaceChanged = false; 163 setSessionSurface(null); 164 } 165 }; 166 TvInteractiveAppView(@onNull Context context)167 public TvInteractiveAppView(@NonNull Context context) { 168 this(context, null, 0); 169 } 170 TvInteractiveAppView(@onNull Context context, @Nullable AttributeSet attrs)171 public TvInteractiveAppView(@NonNull Context context, @Nullable AttributeSet attrs) { 172 this(context, attrs, 0); 173 } 174 TvInteractiveAppView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)175 public TvInteractiveAppView(@NonNull Context context, @Nullable AttributeSet attrs, 176 int defStyleAttr) { 177 super(context, attrs, defStyleAttr); 178 int sourceResId = Resources.getAttributeSetSourceResId(attrs); 179 if (sourceResId != Resources.ID_NULL) { 180 Log.d(TAG, "Build local AttributeSet"); 181 mParser = context.getResources().getXml(sourceResId); 182 mAttrs = Xml.asAttributeSet(mParser); 183 } else { 184 Log.d(TAG, "Use passed in AttributeSet"); 185 mParser = null; 186 mAttrs = attrs; 187 } 188 mDefStyleAttr = defStyleAttr; 189 resetSurfaceView(); 190 mTvInteractiveAppManager = (TvInteractiveAppManager) getContext().getSystemService( 191 Context.TV_INTERACTIVE_APP_SERVICE); 192 } 193 194 /** 195 * Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView. 196 * 197 * @param callback the callback to receive events. MUST NOT be {@code null}. 198 * 199 * @see #clearCallback() 200 */ setCallback( @onNull @allbackExecutor Executor executor, @NonNull TvInteractiveAppCallback callback)201 public void setCallback( 202 @NonNull @CallbackExecutor Executor executor, 203 @NonNull TvInteractiveAppCallback callback) { 204 com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, callback); 205 synchronized (mCallbackLock) { 206 mCallbackExecutor = executor; 207 mCallback = callback; 208 } 209 } 210 211 /** 212 * Clears the callback. 213 * 214 * @see #setCallback(Executor, TvInteractiveAppCallback) 215 */ clearCallback()216 public void clearCallback() { 217 synchronized (mCallbackLock) { 218 mCallback = null; 219 mCallbackExecutor = null; 220 } 221 } 222 223 @Override onAttachedToWindow()224 public void onAttachedToWindow() { 225 super.onAttachedToWindow(); 226 createSessionMediaView(); 227 } 228 229 @Override onDetachedFromWindow()230 public void onDetachedFromWindow() { 231 removeSessionMediaView(); 232 super.onDetachedFromWindow(); 233 } 234 235 @Override onLayout(boolean changed, int left, int top, int right, int bottom)236 public void onLayout(boolean changed, int left, int top, int right, int bottom) { 237 if (DEBUG) { 238 Log.d(TAG, "onLayout (left=" + left + ", top=" + top + ", right=" + right 239 + ", bottom=" + bottom + ",)"); 240 } 241 if (mUseRequestedSurfaceLayout) { 242 mSurfaceView.layout(mSurfaceViewLeft, mSurfaceViewTop, mSurfaceViewRight, 243 mSurfaceViewBottom); 244 } else { 245 mSurfaceView.layout(0, 0, right - left, bottom - top); 246 } 247 } 248 249 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)250 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 251 mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec); 252 int width = mSurfaceView.getMeasuredWidth(); 253 int height = mSurfaceView.getMeasuredHeight(); 254 int childState = mSurfaceView.getMeasuredState(); 255 setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState), 256 resolveSizeAndState(height, heightMeasureSpec, 257 childState << MEASURED_HEIGHT_STATE_SHIFT)); 258 } 259 260 @Override onVisibilityChanged(@onNull View changedView, int visibility)261 public void onVisibilityChanged(@NonNull View changedView, int visibility) { 262 super.onVisibilityChanged(changedView, visibility); 263 mSurfaceView.setVisibility(visibility); 264 if (visibility == View.VISIBLE) { 265 createSessionMediaView(); 266 } else { 267 removeSessionMediaView(); 268 } 269 } 270 resetSurfaceView()271 private void resetSurfaceView() { 272 if (mSurfaceView != null) { 273 mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback); 274 removeView(mSurfaceView); 275 } 276 mSurface = null; 277 mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) { 278 @Override 279 protected void updateSurface() { 280 super.updateSurface(); 281 relayoutSessionMediaView(); 282 }}; 283 // The surface view's content should be treated as secure all the time. 284 mSurfaceView.setSecure(true); 285 mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback); 286 mSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); 287 288 mSurfaceView.setZOrderOnTop(false); 289 mSurfaceView.setZOrderMediaOverlay(true); 290 291 addView(mSurfaceView); 292 } 293 294 /** 295 * Resets this TvInteractiveAppView to release its resources. 296 * 297 * <p>It can be reused by call {@link #prepareInteractiveApp(String, int)}. 298 */ reset()299 public void reset() { 300 if (DEBUG) Log.d(TAG, "reset()"); 301 resetInternal(); 302 } 303 createSessionMediaView()304 private void createSessionMediaView() { 305 // TODO: handle z-order 306 if (mSession == null || !isAttachedToWindow() || mMediaViewCreated) { 307 return; 308 } 309 mMediaViewFrame = getViewFrameOnScreen(); 310 mSession.createMediaView(this, mMediaViewFrame); 311 mMediaViewCreated = true; 312 } 313 removeSessionMediaView()314 private void removeSessionMediaView() { 315 if (mSession == null || !mMediaViewCreated) { 316 return; 317 } 318 mSession.removeMediaView(); 319 mMediaViewCreated = false; 320 mMediaViewFrame = null; 321 } 322 relayoutSessionMediaView()323 private void relayoutSessionMediaView() { 324 if (mSession == null || !isAttachedToWindow() || !mMediaViewCreated) { 325 return; 326 } 327 Rect viewFrame = getViewFrameOnScreen(); 328 if (viewFrame.equals(mMediaViewFrame)) { 329 return; 330 } 331 mSession.relayoutMediaView(viewFrame); 332 mMediaViewFrame = viewFrame; 333 } 334 getViewFrameOnScreen()335 private Rect getViewFrameOnScreen() { 336 Rect frame = new Rect(); 337 getGlobalVisibleRect(frame); 338 RectF frameF = new RectF(frame); 339 getMatrix().mapRect(frameF); 340 frameF.round(frame); 341 return frame; 342 } 343 setSessionSurface(Surface surface)344 private void setSessionSurface(Surface surface) { 345 if (mSession == null) { 346 return; 347 } 348 mSession.setSurface(surface); 349 } 350 dispatchSurfaceChanged(int format, int width, int height)351 private void dispatchSurfaceChanged(int format, int width, int height) { 352 if (mSession == null) { 353 return; 354 } 355 mSession.dispatchSurfaceChanged(format, width, height); 356 } 357 358 private final FinishedInputEventCallback mFinishedInputEventCallback = 359 new FinishedInputEventCallback() { 360 @Override 361 public void onFinishedInputEvent(Object token, boolean handled) { 362 if (DEBUG) { 363 Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" 364 + handled + ")"); 365 } 366 if (handled) { 367 return; 368 } 369 // TODO: Re-order unhandled events. 370 InputEvent event = (InputEvent) token; 371 if (dispatchUnhandledInputEvent(event)) { 372 return; 373 } 374 ViewRootImpl viewRootImpl = getViewRootImpl(); 375 if (viewRootImpl != null) { 376 viewRootImpl.dispatchUnhandledInputEvent(event); 377 } 378 } 379 }; 380 381 /** 382 * Dispatches an unhandled input event to the next receiver. 383 * 384 * It gives the host application a chance to dispatch the unhandled input events. 385 * 386 * @param event The input event. 387 * @return {@code true} if the event was handled by the view, {@code false} otherwise. 388 */ dispatchUnhandledInputEvent(@onNull InputEvent event)389 public boolean dispatchUnhandledInputEvent(@NonNull InputEvent event) { 390 if (mOnUnhandledInputEventListener != null) { 391 if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) { 392 return true; 393 } 394 } 395 return onUnhandledInputEvent(event); 396 } 397 398 /** 399 * Called when an unhandled input event also has not been handled by the user provided 400 * callback. This is the last chance to handle the unhandled input event in the 401 * TvInteractiveAppView. 402 * 403 * @param event The input event. 404 * @return If you handled the event, return {@code true}. If you want to allow the event to be 405 * handled by the next receiver, return {@code false}. 406 */ onUnhandledInputEvent(@onNull InputEvent event)407 public boolean onUnhandledInputEvent(@NonNull InputEvent event) { 408 return false; 409 } 410 411 /** 412 * Sets a listener to be invoked when an input event is not handled 413 * by the TV Interactive App. 414 * 415 * @param listener The callback to be invoked when the unhandled input event is received. 416 */ setOnUnhandledInputEventListener( @onNull @allbackExecutor Executor executor, @NonNull OnUnhandledInputEventListener listener)417 public void setOnUnhandledInputEventListener( 418 @NonNull @CallbackExecutor Executor executor, 419 @NonNull OnUnhandledInputEventListener listener) { 420 mOnUnhandledInputEventListener = listener; 421 // TODO: handle CallbackExecutor 422 } 423 424 /** 425 * Gets the {@link OnUnhandledInputEventListener}. 426 * <p>Returns {@code null} if the listener is not set or is cleared. 427 * 428 * @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener) 429 * @see #clearOnUnhandledInputEventListener() 430 */ 431 @Nullable getOnUnhandledInputEventListener()432 public OnUnhandledInputEventListener getOnUnhandledInputEventListener() { 433 return mOnUnhandledInputEventListener; 434 } 435 436 /** 437 * Clears the {@link OnUnhandledInputEventListener}. 438 */ clearOnUnhandledInputEventListener()439 public void clearOnUnhandledInputEventListener() { 440 mOnUnhandledInputEventListener = null; 441 } 442 443 @Override dispatchKeyEvent(@onNull KeyEvent event)444 public boolean dispatchKeyEvent(@NonNull KeyEvent event) { 445 if (super.dispatchKeyEvent(event)) { 446 return true; 447 } 448 if (mSession == null) { 449 return false; 450 } 451 InputEvent copiedEvent = event.copy(); 452 int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback, 453 mHandler); 454 return ret != Session.DISPATCH_NOT_HANDLED; 455 } 456 457 /** 458 * Prepares the interactive application runtime environment of corresponding 459 * {@link TvInteractiveAppService}. 460 * 461 * @param iAppServiceId the interactive app service ID, which can be found in 462 * {@link TvInteractiveAppServiceInfo#getId()}. 463 * 464 * @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList() 465 */ prepareInteractiveApp( @onNull String iAppServiceId, @TvInteractiveAppServiceInfo.InteractiveAppType int type)466 public void prepareInteractiveApp( 467 @NonNull String iAppServiceId, 468 @TvInteractiveAppServiceInfo.InteractiveAppType int type) { 469 // TODO: document and handle the cases that this method is called multiple times. 470 if (DEBUG) { 471 Log.d(TAG, "prepareInteractiveApp"); 472 } 473 mSessionCallback = new MySessionCallback(iAppServiceId, type); 474 if (mTvInteractiveAppManager != null) { 475 mTvInteractiveAppManager.createSession(iAppServiceId, type, mSessionCallback, mHandler); 476 } 477 } 478 479 /** 480 * Starts the interactive application. 481 */ startInteractiveApp()482 public void startInteractiveApp() { 483 if (DEBUG) { 484 Log.d(TAG, "startInteractiveApp"); 485 } 486 if (mSession != null) { 487 mSession.startInteractiveApp(); 488 } 489 } 490 491 /** 492 * Stops the interactive application. 493 */ stopInteractiveApp()494 public void stopInteractiveApp() { 495 if (DEBUG) { 496 Log.d(TAG, "stopInteractiveApp"); 497 } 498 if (mSession != null) { 499 mSession.stopInteractiveApp(); 500 } 501 } 502 503 /** 504 * Resets the interactive application. 505 * 506 * <p>This releases the resources of the corresponding {@link TvInteractiveAppService.Session}. 507 */ resetInteractiveApp()508 public void resetInteractiveApp() { 509 if (DEBUG) { 510 Log.d(TAG, "resetInteractiveApp"); 511 } 512 if (mSession != null) { 513 mSession.resetInteractiveApp(); 514 } 515 } 516 517 /** 518 * Sends current video bounds to related TV interactive app. 519 * 520 * @param bounds the rectangle area for rendering the current video. 521 */ sendCurrentVideoBounds(@onNull Rect bounds)522 public void sendCurrentVideoBounds(@NonNull Rect bounds) { 523 if (DEBUG) { 524 Log.d(TAG, "sendCurrentVideoBounds"); 525 } 526 if (mSession != null) { 527 mSession.sendCurrentVideoBounds(bounds); 528 } 529 } 530 531 /** 532 * Sends current channel URI to related TV interactive app. 533 * 534 * @param channelUri The current channel URI; {@code null} if there is no currently tuned 535 * channel. 536 */ sendCurrentChannelUri(@ullable Uri channelUri)537 public void sendCurrentChannelUri(@Nullable Uri channelUri) { 538 if (DEBUG) { 539 Log.d(TAG, "sendCurrentChannelUri"); 540 } 541 if (mSession != null) { 542 mSession.sendCurrentChannelUri(channelUri); 543 } 544 } 545 546 /** 547 * Sends current channel logical channel number (LCN) to related TV interactive app. 548 */ sendCurrentChannelLcn(int lcn)549 public void sendCurrentChannelLcn(int lcn) { 550 if (DEBUG) { 551 Log.d(TAG, "sendCurrentChannelLcn"); 552 } 553 if (mSession != null) { 554 mSession.sendCurrentChannelLcn(lcn); 555 } 556 } 557 558 /** 559 * Sends stream volume to related TV interactive app. 560 * 561 * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive. 562 */ sendStreamVolume(float volume)563 public void sendStreamVolume(float volume) { 564 if (DEBUG) { 565 Log.d(TAG, "sendStreamVolume"); 566 } 567 if (mSession != null) { 568 mSession.sendStreamVolume(volume); 569 } 570 } 571 572 /** 573 * Sends track info list to related TV interactive app. 574 */ sendTrackInfoList(@ullable List<TvTrackInfo> tracks)575 public void sendTrackInfoList(@Nullable List<TvTrackInfo> tracks) { 576 if (DEBUG) { 577 Log.d(TAG, "sendTrackInfoList"); 578 } 579 if (mSession != null) { 580 mSession.sendTrackInfoList(tracks); 581 } 582 } 583 584 /** 585 * Sends current TV input ID to related TV interactive app. 586 * 587 * @param inputId The current TV input ID whose channel is tuned. {@code null} if no channel is 588 * tuned. 589 * @see android.media.tv.TvInputInfo 590 */ sendCurrentTvInputId(@ullable String inputId)591 public void sendCurrentTvInputId(@Nullable String inputId) { 592 if (DEBUG) { 593 Log.d(TAG, "sendCurrentTvInputId"); 594 } 595 if (mSession != null) { 596 mSession.sendCurrentTvInputId(inputId); 597 } 598 } 599 600 /** 601 * Sends the current time shift mode to the TV interactive app bound to this view 602 * 603 * @param mode The current time shift mode. The value is one of the following: 604 * {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL}, 605 * {@link TvInputManager#TIME_SHIFT_MODE_NETWORK}, 606 * {@link TvInputManager#TIME_SHIFT_MODE_AUTO}. 607 */ sendTimeShiftMode(@ndroid.media.tv.TvInputManager.TimeShiftMode int mode)608 public void sendTimeShiftMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) { 609 if (DEBUG) { 610 Log.d(TAG, "sendTimeShiftMode"); 611 } 612 if (mSession != null) { 613 mSession.sendTimeShiftMode(mode); 614 } 615 } 616 617 /** 618 * Sends the available supported playback speeds to the TV interactive app bound to this view. 619 * 620 * @param speeds An ordered array of playback speeds, expressed as values relative to the 621 * normal playback speed (1.0), at which the current content can be played as 622 * a time-shifted broadcast. This is an empty array if the supported playback 623 * speeds are unknown or the video/broadcast is not in time shift mode. If 624 * currently in time shift mode, this array will normally include at least 625 * the values 1.0 (normal speed) and 0.0 (paused). 626 * @see PlaybackParams#getSpeed() 627 */ sendAvailableSpeeds(@onNull float[] speeds)628 public void sendAvailableSpeeds(@NonNull float[] speeds) { 629 if (DEBUG) { 630 Log.d(TAG, "sendAvailableSpeeds"); 631 } 632 if (mSession != null) { 633 Arrays.sort(speeds); 634 mSession.sendAvailableSpeeds(speeds); 635 } 636 } 637 638 /** 639 * Sends the requested {@link android.media.tv.TvRecordingInfo}. 640 * 641 * @see TvInteractiveAppService.Session#requestTvRecordingInfo(String) 642 * @param recordingInfo The recording info requested. {@code null} if no recording found. 643 */ sendTvRecordingInfo(@ullable TvRecordingInfo recordingInfo)644 public void sendTvRecordingInfo(@Nullable TvRecordingInfo recordingInfo) { 645 if (DEBUG) { 646 Log.d(TAG, "sendTvRecordingInfo"); 647 } 648 if (mSession != null) { 649 mSession.sendTvRecordingInfo(recordingInfo); 650 } 651 } 652 653 /** 654 * Sends the requested {@link android.media.tv.TvRecordingInfo}. 655 * 656 * @see TvInteractiveAppService.Session#requestTvRecordingInfoList(int) 657 * @param recordingInfoList The list of recording info requested. Returns an empty list if no 658 * matching recording info found. 659 */ sendTvRecordingInfoList(@onNull List<TvRecordingInfo> recordingInfoList)660 public void sendTvRecordingInfoList(@NonNull List<TvRecordingInfo> recordingInfoList) { 661 if (DEBUG) { 662 Log.d(TAG, "sendTvRecordingInfoList"); 663 } 664 if (mSession != null) { 665 mSession.sendTvRecordingInfoList(recordingInfoList); 666 } 667 } 668 669 /** 670 * Alerts the related TV interactive app service that a recording has been started. 671 * 672 * @param recordingId The ID of the recording started. This ID is created and maintained by the 673 * TV app and is used to identify the recording in the future. 674 * 675 * @param requestId The ID of the request when 676 * {@link TvInteractiveAppService.Session#requestStartRecording(String, Uri)} 677 * is called. {@code null} if the recording is not triggered by a request. 678 * This ID should be created by the {@link TvInteractiveAppService} and 679 * can be any string. 680 * @see TvInteractiveAppView#notifyRecordingStopped(String) 681 */ notifyRecordingStarted(@onNull String recordingId, @Nullable String requestId)682 public void notifyRecordingStarted(@NonNull String recordingId, @Nullable String requestId) { 683 if (DEBUG) { 684 Log.d(TAG, "notifyRecordingStarted"); 685 } 686 if (mSession != null) { 687 mSession.notifyRecordingStarted(recordingId, requestId); 688 } 689 } 690 691 /** 692 * Alerts the TV interactive app that a recording has been stopped. 693 * 694 * @param recordingId The ID of the recording stopped. This ID is created and maintained 695 * by the TV app when a recording is started. 696 * @see TvInteractiveAppView#notifyRecordingStarted(String, String) 697 */ notifyRecordingStopped(@onNull String recordingId)698 public void notifyRecordingStopped(@NonNull String recordingId) { 699 if (DEBUG) { 700 Log.d(TAG, "notifyRecordingStopped"); 701 } 702 if (mSession != null) { 703 mSession.notifyRecordingStopped(recordingId); 704 } 705 } 706 707 /** 708 * Sends signing result to related TV interactive app. 709 * 710 * <p>This is used when the corresponding server of the broadcast-independent interactive 711 * app requires signing during handshaking, and the interactive app service doesn't have 712 * the built-in private key. The private key is provided by the content providers and 713 * pre-built in the related app, such as TV app. 714 * 715 * @param signingId the ID to identify the request. It's the same as the corresponding ID in 716 * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} 717 * @param result the signed result. 718 */ sendSigningResult(@onNull String signingId, @NonNull byte[] result)719 public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) { 720 if (DEBUG) { 721 Log.d(TAG, "sendSigningResult"); 722 } 723 if (mSession != null) { 724 mSession.sendSigningResult(signingId, result); 725 } 726 } 727 728 /** 729 * Notifies the corresponding {@link TvInteractiveAppService} when there is an error. 730 * 731 * @param errMsg the message of the error. 732 * @param params additional parameters of the error. For example, the signingId of {@link 733 * TvInteractiveAppCallback#onRequestSigning(String, String, String, String, byte[])} can be 734 * included to identify the related signing request, and the method name "onRequestSigning" 735 * can also be added to the params. 736 * 737 * @see #ERROR_KEY_METHOD_NAME 738 */ notifyError(@onNull String errMsg, @NonNull Bundle params)739 public void notifyError(@NonNull String errMsg, @NonNull Bundle params) { 740 if (DEBUG) { 741 Log.d(TAG, "notifyError msg=" + errMsg + "; params=" + params); 742 } 743 if (mSession != null) { 744 mSession.notifyError(errMsg, params); 745 } 746 } 747 748 /** 749 * Notifies the corresponding {@link TvInteractiveAppService} when a time shift 750 * {@link android.media.PlaybackParams} is set or changed. 751 * 752 * @see TvView#timeShiftSetPlaybackParams(PlaybackParams) 753 * @param params The new {@link PlaybackParams} that was set or changed. 754 */ notifyTimeShiftPlaybackParams(@onNull PlaybackParams params)755 public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) { 756 if (DEBUG) { 757 Log.d(TAG, "notifyTimeShiftPlaybackParams params=" + params); 758 } 759 if (mSession != null) { 760 mSession.notifyTimeShiftPlaybackParams(params); 761 } 762 } 763 764 /** 765 * Notifies the corresponding {@link TvInteractiveAppService} when time shift 766 * status is changed. 767 * 768 * @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int) 769 * @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int) 770 * @param inputId The ID of the input for which the time shift status has changed. 771 * @param status The status of which the input has changed to. Should be one of the 772 * following. 773 * <ul> 774 * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNKNOWN} 775 * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED} 776 * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE} 777 * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} 778 * </ul> 779 */ notifyTimeShiftStatusChanged( @onNull String inputId, @TvInputManager.TimeShiftStatus int status)780 public void notifyTimeShiftStatusChanged( 781 @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) { 782 if (DEBUG) { 783 Log.d(TAG, 784 "notifyTimeShiftStatusChanged inputId=" + inputId + "; status=" + status); 785 } 786 if (mSession != null) { 787 mSession.notifyTimeShiftStatusChanged(inputId, status); 788 } 789 } 790 791 /** 792 * Notifies the corresponding {@link TvInteractiveAppService} when time shift 793 * start position is changed. 794 * 795 * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long) 796 * @param inputId The ID of the input for which the time shift start position has changed. 797 * @param timeMs The start position for time shifting, in milliseconds since the epoch. 798 */ notifyTimeShiftStartPositionChanged(@onNull String inputId, long timeMs)799 public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) { 800 if (DEBUG) { 801 Log.d(TAG, "notifyTimeShiftStartPositionChanged inputId=" + inputId 802 + "; timeMs=" + timeMs); 803 } 804 if (mSession != null) { 805 mSession.notifyTimeShiftStartPositionChanged(inputId, timeMs); 806 } 807 } 808 809 /** 810 * Notifies the corresponding {@link TvInteractiveAppService} when time shift 811 * current position is changed. 812 * 813 * @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long) 814 * @param inputId The ID of the input for which the time shift current position has changed. 815 * @param timeMs The current position for time shifting, in milliseconds since the epoch. 816 */ notifyTimeShiftCurrentPositionChanged(@onNull String inputId, long timeMs)817 public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) { 818 if (DEBUG) { 819 Log.d(TAG, "notifyTimeShiftCurrentPositionChanged inputId=" + inputId 820 + "; timeMs=" + timeMs); 821 } 822 if (mSession != null) { 823 mSession.notifyTimeShiftCurrentPositionChanged(inputId, timeMs); 824 } 825 } 826 827 /** 828 * This is called to notify the corresponding interactive app service when an error occurred 829 * while establishing a connection to the recording session for the corresponding TV input. 830 * 831 * @param recordingId The ID of the related recording which is sent via 832 * {@link #notifyRecordingStarted(String, String)} 833 * @param inputId The ID of the TV input bound to the current TvRecordingClient. 834 * @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String) 835 * @hide 836 */ notifyRecordingConnectionFailed( @onNull String recordingId, @NonNull String inputId)837 public void notifyRecordingConnectionFailed( 838 @NonNull String recordingId, @NonNull String inputId) { 839 if (DEBUG) { 840 Log.d(TAG, "notifyRecordingConnectionFailed recordingId=" + recordingId 841 + "; inputId=" + inputId); 842 } 843 if (mSession != null) { 844 mSession.notifyRecordingConnectionFailed(recordingId, inputId); 845 } 846 } 847 848 /** 849 * This is called to notify the corresponding interactive app service when the connection to 850 * the current recording session is lost. 851 * 852 * @param recordingId The ID of the related recording which is sent via 853 * {@link #notifyRecordingStarted(String, String)} 854 * @param inputId The ID of the TV input bound to the current TvRecordingClient. 855 * @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String) 856 * @hide 857 */ notifyRecordingDisconnected( @onNull String recordingId, @NonNull String inputId)858 public void notifyRecordingDisconnected( 859 @NonNull String recordingId, @NonNull String inputId) { 860 if (DEBUG) { 861 Log.d(TAG, "notifyRecordingDisconnected recordingId=" + recordingId 862 + "; inputId=" + inputId); 863 } 864 if (mSession != null) { 865 mSession.notifyRecordingDisconnected(recordingId, inputId); 866 } 867 } 868 869 /** 870 * This is called to notify the corresponding interactive app service when the recording session 871 * has been tuned to the given channel and is ready to start recording. 872 * 873 * @param recordingId The ID of the related recording which is sent via 874 * {@link #notifyRecordingStarted(String, String)} 875 * @param channelUri The URI of the tuned channel. 876 * @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri) 877 * @hide 878 */ notifyRecordingTuned( @onNull String recordingId, @NonNull Uri channelUri)879 public void notifyRecordingTuned( 880 @NonNull String recordingId, @NonNull Uri channelUri) { 881 if (DEBUG) { 882 Log.d(TAG, "notifyRecordingTuned recordingId=" + recordingId 883 + "; channelUri=" + channelUri); 884 } 885 if (mSession != null) { 886 mSession.notifyRecordingTuned(recordingId, channelUri); 887 } 888 } 889 890 /** 891 * This is called to notify the corresponding interactive app service when an issue has 892 * occurred. It may be called at any time after the current recording session is created until 893 * it is released. 894 * 895 * @param recordingId The ID of the related recording which is sent via 896 * {@link #notifyRecordingStarted(String, String)} 897 * @param err The error code. Should be one of the following. 898 * <ul> 899 * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN} 900 * <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE} 901 * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY} 902 * </ul> 903 * @see android.media.tv.TvRecordingClient.RecordingCallback#onError(int) 904 * @hide 905 */ notifyRecordingError( @onNull String recordingId, @TvInputManager.RecordingError int err)906 public void notifyRecordingError( 907 @NonNull String recordingId, @TvInputManager.RecordingError int err) { 908 if (DEBUG) { 909 Log.d(TAG, "notifyRecordingError recordingId=" + recordingId 910 + "; err=" + err); 911 } 912 if (mSession != null) { 913 mSession.notifyRecordingError(recordingId, err); 914 } 915 } 916 917 /** 918 * This is called to notify the corresponding interactive app service when the recording has 919 * been scheduled. 920 * 921 * @param recordingId The ID assigned to this recording by the app. It can be used to send 922 * recording related requests such as 923 * {@link TvInteractiveAppService.Session#requestStopRecording(String)}. 924 * @param requestId The ID of the request when 925 * {@link TvInteractiveAppService.Session#requestScheduleRecording} is called. 926 * {@code null} if the recording is not triggered by a request. 927 * This ID should be created by the {@link TvInteractiveAppService} and 928 * can be any string. 929 */ notifyRecordingScheduled( @onNull String recordingId, @Nullable String requestId)930 public void notifyRecordingScheduled( 931 @NonNull String recordingId, @Nullable String requestId) { 932 if (DEBUG) { 933 Log.d(TAG, "notifyRecordingScheduled recordingId=" + recordingId 934 + "; requestId=" + requestId); 935 } 936 if (mSession != null) { 937 mSession.notifyRecordingScheduled(recordingId, requestId); 938 } 939 } 940 941 /** 942 * This is called to notify the corresponding interactive app service when a new TV message 943 * is received. 944 * 945 * @param type The type of message received, such as 946 * {@link TvInputManager#TV_MESSAGE_TYPE_WATERMARK} 947 * @param data The raw data of the message. The bundle keys are: 948 * {@link TvInputManager#TV_MESSAGE_KEY_STREAM_ID}, 949 * {@link TvInputManager#TV_MESSAGE_KEY_GROUP_ID}, 950 * {@link TvInputManager#TV_MESSAGE_KEY_SUBTYPE}, 951 * {@link TvInputManager#TV_MESSAGE_KEY_RAW_DATA}. 952 * See {@link TvInputManager#TV_MESSAGE_KEY_SUBTYPE} for more information on 953 * how to parse this data. 954 */ notifyTvMessage(@onNull @vInputManager.TvMessageType int type, @NonNull Bundle data)955 public void notifyTvMessage(@NonNull @TvInputManager.TvMessageType int type, 956 @NonNull Bundle data) { 957 if (DEBUG) { 958 Log.d(TAG, "notifyTvMessage type=" + type 959 + "; data=" + data); 960 } 961 if (mSession != null) { 962 mSession.notifyTvMessage(type, data); 963 } 964 } 965 resetInternal()966 private void resetInternal() { 967 mSessionCallback = null; 968 if (mSession != null) { 969 setSessionSurface(null); 970 removeSessionMediaView(); 971 mUseRequestedSurfaceLayout = false; 972 mSession.release(); 973 mSession = null; 974 resetSurfaceView(); 975 } 976 } 977 978 /** 979 * Creates broadcast-independent(BI) interactive application. 980 * 981 * <p>{@link TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)} will be 982 * called for the result. 983 * 984 * @param biIAppUri URI associated this BI interactive app. 985 * @param params optional parameters for broadcast-independent interactive application, such as 986 * {@link #BI_INTERACTIVE_APP_KEY_CERTIFICATE}. 987 * 988 * @see TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String) 989 * @see #BI_INTERACTIVE_APP_KEY_CERTIFICATE 990 * @see #BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS 991 * @see #BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT 992 */ createBiInteractiveApp(@onNull Uri biIAppUri, @Nullable Bundle params)993 public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) { 994 if (DEBUG) { 995 Log.d(TAG, "createBiInteractiveApp Uri=" + biIAppUri + ", params=" + params); 996 } 997 if (mSession != null) { 998 mSession.createBiInteractiveApp(biIAppUri, params); 999 } 1000 } 1001 1002 /** 1003 * Destroys broadcast-independent(BI) interactive application. 1004 * 1005 * @param biIAppId the BI interactive app ID from {@link #createBiInteractiveApp(Uri, Bundle)} 1006 * 1007 * @see #createBiInteractiveApp(Uri, Bundle) 1008 */ destroyBiInteractiveApp(@onNull String biIAppId)1009 public void destroyBiInteractiveApp(@NonNull String biIAppId) { 1010 if (DEBUG) { 1011 Log.d(TAG, "destroyBiInteractiveApp biIAppId=" + biIAppId); 1012 } 1013 if (mSession != null) { 1014 mSession.destroyBiInteractiveApp(biIAppId); 1015 } 1016 } 1017 1018 /** @hide */ getInteractiveAppSession()1019 public Session getInteractiveAppSession() { 1020 return mSession; 1021 } 1022 1023 /** 1024 * Sets the TvInteractiveAppView to receive events from TIS. This method links the session of 1025 * TvInteractiveAppManager to TvInputManager session, so the TIAS can get the TIS events. 1026 * 1027 * @param tvView the TvView to be linked to this TvInteractiveAppView via linking of Sessions. 1028 * @return The result of the operation. 1029 */ setTvView(@ullable TvView tvView)1030 public int setTvView(@Nullable TvView tvView) { 1031 if (tvView == null) { 1032 return unsetTvView(); 1033 } 1034 TvInputManager.Session inputSession = tvView.getInputSession(); 1035 if (inputSession == null || mSession == null) { 1036 return SET_TVVIEW_FAIL; 1037 } 1038 mSession.setInputSession(inputSession); 1039 inputSession.setInteractiveAppSession(mSession); 1040 return SET_TVVIEW_SUCCESS; 1041 } 1042 unsetTvView()1043 private int unsetTvView() { 1044 if (mSession == null || mSession.getInputSession() == null) { 1045 return UNSET_TVVIEW_FAIL; 1046 } 1047 mSession.getInputSession().setInteractiveAppSession(null); 1048 mSession.setInputSession(null); 1049 return UNSET_TVVIEW_SUCCESS; 1050 } 1051 1052 /** 1053 * To toggle Digital Teletext Application if there is one in AIT app list. 1054 * 1055 * <p>A Teletext Application is a broadcast-related application to display text and basic 1056 * graphics. 1057 * 1058 * @param enable {@code true} to enable Teletext app; {@code false} to disable it. 1059 */ setTeletextAppEnabled(boolean enable)1060 public void setTeletextAppEnabled(boolean enable) { 1061 if (DEBUG) { 1062 Log.d(TAG, "setTeletextAppEnabled enable=" + enable); 1063 } 1064 if (mSession != null) { 1065 mSession.setTeletextAppEnabled(enable); 1066 } 1067 } 1068 1069 /** 1070 * Callback used to receive various status updates on the {@link TvInteractiveAppView}. 1071 */ 1072 public abstract static class TvInteractiveAppCallback { 1073 // TODO: unhide the following public APIs 1074 1075 /** 1076 * This is called when a playback command is requested to be processed by the related TV 1077 * input. 1078 * 1079 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1080 * @param cmdType type of the command 1081 * @param parameters parameters of the command 1082 */ onPlaybackCommandRequest( @onNull String iAppServiceId, @NonNull @TvInteractiveAppService.PlaybackCommandType String cmdType, @NonNull Bundle parameters)1083 public void onPlaybackCommandRequest( 1084 @NonNull String iAppServiceId, 1085 @NonNull @TvInteractiveAppService.PlaybackCommandType String cmdType, 1086 @NonNull Bundle parameters) { 1087 } 1088 1089 /** 1090 * This is called when a time shift command is requested to be processed by the related TV 1091 * input. 1092 * 1093 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1094 * @param cmdType type of the command 1095 * @param parameters parameters of the command 1096 */ onTimeShiftCommandRequest( @onNull String iAppServiceId, @NonNull @TvInteractiveAppService.TimeShiftCommandType String cmdType, @NonNull Bundle parameters)1097 public void onTimeShiftCommandRequest( 1098 @NonNull String iAppServiceId, 1099 @NonNull @TvInteractiveAppService.TimeShiftCommandType String cmdType, 1100 @NonNull Bundle parameters) { 1101 } 1102 1103 /** 1104 * This is called when the state of corresponding interactive app is changed. 1105 * 1106 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1107 * @param state the current state. 1108 * @param err the error code for error state. {@link TvInteractiveAppManager#ERROR_NONE} 1109 * is used when the state is not 1110 * {@link TvInteractiveAppManager#INTERACTIVE_APP_STATE_ERROR}. 1111 */ onStateChanged( @onNull String iAppServiceId, @TvInteractiveAppManager.InteractiveAppState int state, @TvInteractiveAppManager.ErrorCode int err)1112 public void onStateChanged( 1113 @NonNull String iAppServiceId, 1114 @TvInteractiveAppManager.InteractiveAppState int state, 1115 @TvInteractiveAppManager.ErrorCode int err) { 1116 } 1117 1118 /** 1119 * This is called when broadcast-independent (BI) interactive app is created. 1120 * 1121 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1122 * @param biIAppUri URI associated this BI interactive app. This is the same URI in 1123 * {@link #createBiInteractiveApp(Uri, Bundle)} 1124 * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive 1125 * app. {@code null} if it's not created successfully. 1126 * 1127 * @see #createBiInteractiveApp(Uri, Bundle) 1128 * @see #destroyBiInteractiveApp(String) 1129 */ onBiInteractiveAppCreated(@onNull String iAppServiceId, @NonNull Uri biIAppUri, @Nullable String biIAppId)1130 public void onBiInteractiveAppCreated(@NonNull String iAppServiceId, @NonNull Uri biIAppUri, 1131 @Nullable String biIAppId) { 1132 } 1133 1134 /** 1135 * This is called when the digital teletext app state is changed. 1136 * 1137 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1138 * @param state digital teletext app current state. 1139 */ onTeletextAppStateChanged( @onNull String iAppServiceId, @TvInteractiveAppManager.TeletextAppState int state)1140 public void onTeletextAppStateChanged( 1141 @NonNull String iAppServiceId, 1142 @TvInteractiveAppManager.TeletextAppState int state) { 1143 } 1144 1145 /** 1146 * This is called when {@link TvInteractiveAppService.Session#setVideoBounds(Rect)} is 1147 * called. 1148 * 1149 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1150 */ onSetVideoBounds(@onNull String iAppServiceId, @NonNull Rect rect)1151 public void onSetVideoBounds(@NonNull String iAppServiceId, @NonNull Rect rect) { 1152 } 1153 1154 /** 1155 * This is called when {@link TvInteractiveAppService.Session#requestCurrentVideoBounds()} 1156 * is called. 1157 * 1158 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1159 */ onRequestCurrentVideoBounds(@onNull String iAppServiceId)1160 public void onRequestCurrentVideoBounds(@NonNull String iAppServiceId) { 1161 } 1162 1163 /** 1164 * This is called when {@link TvInteractiveAppService.Session#requestCurrentChannelUri()} is 1165 * called. 1166 * 1167 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1168 */ onRequestCurrentChannelUri(@onNull String iAppServiceId)1169 public void onRequestCurrentChannelUri(@NonNull String iAppServiceId) { 1170 } 1171 1172 /** 1173 * This is called when {@link TvInteractiveAppService.Session#requestCurrentChannelLcn()} is 1174 * called. 1175 * 1176 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1177 */ onRequestCurrentChannelLcn(@onNull String iAppServiceId)1178 public void onRequestCurrentChannelLcn(@NonNull String iAppServiceId) { 1179 } 1180 1181 /** 1182 * This is called when {@link TvInteractiveAppService.Session#requestStreamVolume()} is 1183 * called. 1184 * 1185 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1186 */ onRequestStreamVolume(@onNull String iAppServiceId)1187 public void onRequestStreamVolume(@NonNull String iAppServiceId) { 1188 } 1189 1190 /** 1191 * This is called when {@link TvInteractiveAppService.Session#requestTrackInfoList()} is 1192 * called. 1193 * 1194 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1195 */ onRequestTrackInfoList(@onNull String iAppServiceId)1196 public void onRequestTrackInfoList(@NonNull String iAppServiceId) { 1197 } 1198 1199 /** 1200 * This is called when {@link TvInteractiveAppService.Session#requestCurrentTvInputId()} is 1201 * called. 1202 * 1203 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1204 */ onRequestCurrentTvInputId(@onNull String iAppServiceId)1205 public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) { 1206 } 1207 1208 /** 1209 * This is called when {@link TvInteractiveAppService.Session#requestTimeShiftMode()} is 1210 * called. 1211 * 1212 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1213 */ onRequestTimeShiftMode(@onNull String iAppServiceId)1214 public void onRequestTimeShiftMode(@NonNull String iAppServiceId) { 1215 } 1216 1217 /** 1218 * This is called when {@link TvInteractiveAppService.Session#requestAvailableSpeeds()} is 1219 * called. 1220 * 1221 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1222 */ onRequestAvailableSpeeds(@onNull String iAppServiceId)1223 public void onRequestAvailableSpeeds(@NonNull String iAppServiceId) { 1224 } 1225 1226 /** 1227 * This is called when 1228 * {@link TvInteractiveAppService.Session#requestStartRecording(String, Uri)} is called. 1229 * 1230 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1231 * @param requestId The ID of this request which is used to match the corresponding 1232 * response. The request ID in 1233 * {@link #notifyRecordingStarted(String, String)} for this request is the 1234 * same as the ID sent here. This should be defined by the 1235 * TIAS and can be any string. Should this API be called with the 1236 * same requestId twice, both requests should be handled regardless 1237 * by the TV application. 1238 * @param programUri The URI of the program to record 1239 * 1240 */ onRequestStartRecording(@onNull String iAppServiceId, @NonNull String requestId, @Nullable Uri programUri)1241 public void onRequestStartRecording(@NonNull String iAppServiceId, 1242 @NonNull String requestId, @Nullable Uri programUri) { 1243 } 1244 1245 /** 1246 * This is called when {@link TvInteractiveAppService.Session#requestStopRecording(String)} 1247 * is called. 1248 * 1249 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1250 * @param recordingId The ID of the recording to stop. This is provided by the TV app in 1251 * {@link #notifyRecordingStarted(String, String)} 1252 * @see #notifyRecordingStarted(String, String) 1253 * @see #notifyRecordingStopped(String) 1254 */ onRequestStopRecording( @onNull String iAppServiceId, @NonNull String recordingId)1255 public void onRequestStopRecording( 1256 @NonNull String iAppServiceId, 1257 @NonNull String recordingId) { 1258 } 1259 1260 /** 1261 * This is called when 1262 * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)} 1263 * is called. 1264 * 1265 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1266 * @param requestId The ID of this request which is used to match the corresponding 1267 * response. The request ID in 1268 * {@link #notifyRecordingScheduled(String, String)} for this request is 1269 * the same as the ID sent here. This should be defined by the 1270 * TIAS and can be any string. Should this API be called with the 1271 * same requestId twice, both requests should be handled regardless 1272 * by the TV application. 1273 * @param inputId The ID of the TV input for the given channel. 1274 * @param channelUri The URI of a channel to be recorded. 1275 * @param programUri The URI of the TV program to be recorded. 1276 * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped 1277 * name, i.e. prefixed with a package name you own, so that different developers 1278 * will not create conflicting keys. 1279 * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle) 1280 * @see android.media.tv.TvRecordingClient#startRecording(Uri) 1281 */ onRequestScheduleRecording(@onNull String iAppServiceId, @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params)1282 public void onRequestScheduleRecording(@NonNull String iAppServiceId, 1283 @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, 1284 @NonNull Uri programUri, @NonNull Bundle params) { 1285 } 1286 1287 /** 1288 * This is called when 1289 * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)} 1290 * is called. 1291 * 1292 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1293 * @param requestId The ID of this request which is used to match the corresponding 1294 * response. The request ID in 1295 * {@link #notifyRecordingScheduled(String, String)} for this request is 1296 * the same as the ID sent here. This should be defined by the 1297 * TIAS and can be any string. Should this API be called with the 1298 * same requestId twice, both requests should be handled regardless 1299 * by the TV application. 1300 * @param inputId The ID of the TV input for the given channel. 1301 * @param channelUri The URI of a channel to be recorded. 1302 * @param startTime The start time of the recording in milliseconds since epoch. 1303 * @param duration The duration of the recording in milliseconds. 1304 * @param repeatDays The repeated days. 0 if not repeated. 1305 * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped 1306 * name, i.e. prefixed with a package name you own, so that different developers 1307 * will not create conflicting keys. 1308 * @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle) 1309 * @see android.media.tv.TvRecordingClient#startRecording(Uri) 1310 */ onRequestScheduleRecording(@onNull String iAppServiceId, @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration, int repeatDays, @NonNull Bundle params)1311 public void onRequestScheduleRecording(@NonNull String iAppServiceId, 1312 @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, 1313 long startTime, long duration, int repeatDays, @NonNull Bundle params) { 1314 } 1315 1316 /** 1317 * This is called when 1318 * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is 1319 * called. 1320 * 1321 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1322 * @param signingId the ID to identify the request. 1323 * @param algorithm the standard name of the signature algorithm requested, such as 1324 * MD5withRSA, SHA256withDSA, etc. 1325 * @param alias the alias of the corresponding {@link java.security.KeyStore}. 1326 * @param data the original bytes to be signed. 1327 */ onRequestSigning(@onNull String iAppServiceId, @NonNull String signingId, @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data)1328 public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId, 1329 @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) { 1330 } 1331 1332 /** 1333 * This is called when {@link TvInteractiveAppService.Session#setTvRecordingInfo(String, 1334 * TvRecordingInfo)} is called. 1335 * 1336 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1337 * @param recordingId The ID of the recording to set the info for. This is provided by the 1338 * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)} 1339 * @param recordingInfo The {@link TvRecordingInfo} to set to the recording. 1340 */ onSetTvRecordingInfo( @onNull String iAppServiceId, @NonNull String recordingId, @NonNull TvRecordingInfo recordingInfo)1341 public void onSetTvRecordingInfo( 1342 @NonNull String iAppServiceId, 1343 @NonNull String recordingId, 1344 @NonNull TvRecordingInfo recordingInfo) { 1345 } 1346 1347 /** 1348 * This is called when 1349 * {@link TvInteractiveAppService.Session#requestTvRecordingInfo(String)} is 1350 * called. 1351 * 1352 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1353 * @param recordingId The ID of the recording to get the info for. This is provided by the 1354 * TV app in 1355 * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)} 1356 */ onRequestTvRecordingInfo( @onNull String iAppServiceId, @NonNull String recordingId)1357 public void onRequestTvRecordingInfo( 1358 @NonNull String iAppServiceId, 1359 @NonNull String recordingId) { 1360 } 1361 1362 /** 1363 * This is called when 1364 * {@link TvInteractiveAppService.Session#requestTvRecordingInfoList(int)} is 1365 * called. 1366 * 1367 * @param iAppServiceId The ID of the TV interactive app service bound to this view. 1368 * @param type The type of recording requested to retrieve. 1369 */ onRequestTvRecordingInfoList( @onNull String iAppServiceId, @TvRecordingInfo.TvRecordingListType int type)1370 public void onRequestTvRecordingInfoList( 1371 @NonNull String iAppServiceId, 1372 @TvRecordingInfo.TvRecordingListType int type) { 1373 } 1374 } 1375 1376 /** 1377 * Interface definition for a callback to be invoked when the unhandled input event is received. 1378 */ 1379 public interface OnUnhandledInputEventListener { 1380 /** 1381 * Called when an input event was not handled by the TV Interactive App. 1382 * 1383 * <p>This is called asynchronously from where the event is dispatched. It gives the host 1384 * application a chance to handle the unhandled input events. 1385 * 1386 * @param event The input event. 1387 * @return If you handled the event, return {@code true}. If you want to allow the event to 1388 * be handled by the next receiver, return {@code false}. 1389 */ onUnhandledInputEvent(@onNull InputEvent event)1390 boolean onUnhandledInputEvent(@NonNull InputEvent event); 1391 } 1392 1393 private class MySessionCallback extends SessionCallback { 1394 final String mIAppServiceId; 1395 int mType; 1396 MySessionCallback(String iAppServiceId, int type)1397 MySessionCallback(String iAppServiceId, int type) { 1398 mIAppServiceId = iAppServiceId; 1399 mType = type; 1400 } 1401 1402 @Override onSessionCreated(Session session)1403 public void onSessionCreated(Session session) { 1404 if (DEBUG) { 1405 Log.d(TAG, "onSessionCreated()"); 1406 } 1407 if (this != mSessionCallback) { 1408 Log.w(TAG, "onSessionCreated - session already created"); 1409 // This callback is obsolete. 1410 if (session != null) { 1411 session.release(); 1412 } 1413 return; 1414 } 1415 mSession = session; 1416 if (session != null) { 1417 // mSurface may not be ready yet as soon as starting an application. 1418 // In the case, we don't send Session.setSurface(null) unnecessarily. 1419 // setSessionSurface will be called in surfaceCreated. 1420 if (mSurface != null) { 1421 setSessionSurface(mSurface); 1422 if (mSurfaceChanged) { 1423 dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight); 1424 } 1425 } 1426 createSessionMediaView(); 1427 } else { 1428 // Failed to create 1429 // Todo: forward error to Tv App 1430 mSessionCallback = null; 1431 } 1432 } 1433 1434 @Override onSessionReleased(Session session)1435 public void onSessionReleased(Session session) { 1436 if (DEBUG) { 1437 Log.d(TAG, "onSessionReleased()"); 1438 } 1439 if (this != mSessionCallback) { 1440 Log.w(TAG, "onSessionReleased - session not created"); 1441 return; 1442 } 1443 mMediaViewCreated = false; 1444 mMediaViewFrame = null; 1445 mSessionCallback = null; 1446 mSession = null; 1447 } 1448 1449 @Override onLayoutSurface(Session session, int left, int top, int right, int bottom)1450 public void onLayoutSurface(Session session, int left, int top, int right, int bottom) { 1451 if (DEBUG) { 1452 Log.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top + ", right=" 1453 + right + ", bottom=" + bottom + ",)"); 1454 } 1455 if (this != mSessionCallback) { 1456 Log.w(TAG, "onLayoutSurface - session not created"); 1457 return; 1458 } 1459 mSurfaceViewLeft = left; 1460 mSurfaceViewTop = top; 1461 mSurfaceViewRight = right; 1462 mSurfaceViewBottom = bottom; 1463 mUseRequestedSurfaceLayout = true; 1464 requestLayout(); 1465 } 1466 1467 @Override onCommandRequest( Session session, @TvInteractiveAppService.PlaybackCommandType String cmdType, Bundle parameters)1468 public void onCommandRequest( 1469 Session session, 1470 @TvInteractiveAppService.PlaybackCommandType String cmdType, 1471 Bundle parameters) { 1472 if (DEBUG) { 1473 Log.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters=" 1474 + parameters.toString() + ")"); 1475 } 1476 if (this != mSessionCallback) { 1477 Log.w(TAG, "onCommandRequest - session not created"); 1478 return; 1479 } 1480 synchronized (mCallbackLock) { 1481 if (mCallbackExecutor != null) { 1482 mCallbackExecutor.execute(() -> { 1483 synchronized (mCallbackLock) { 1484 if (mCallback != null) { 1485 mCallback.onPlaybackCommandRequest( 1486 mIAppServiceId, cmdType, parameters); 1487 } 1488 } 1489 }); 1490 } 1491 } 1492 } 1493 1494 @Override onTimeShiftCommandRequest( Session session, @TvInteractiveAppService.TimeShiftCommandType String cmdType, Bundle parameters)1495 public void onTimeShiftCommandRequest( 1496 Session session, 1497 @TvInteractiveAppService.TimeShiftCommandType String cmdType, 1498 Bundle parameters) { 1499 if (DEBUG) { 1500 Log.d(TAG, "onTimeShiftCommandRequest (cmdType=" + cmdType + ", parameters=" 1501 + parameters.toString() + ")"); 1502 } 1503 if (this != mSessionCallback) { 1504 Log.w(TAG, "onTimeShiftCommandRequest - session not created"); 1505 return; 1506 } 1507 synchronized (mCallbackLock) { 1508 if (mCallbackExecutor != null) { 1509 mCallbackExecutor.execute(() -> { 1510 synchronized (mCallbackLock) { 1511 if (mCallback != null) { 1512 mCallback.onTimeShiftCommandRequest( 1513 mIAppServiceId, cmdType, parameters); 1514 } 1515 } 1516 }); 1517 } 1518 } 1519 } 1520 1521 @Override onSessionStateChanged( Session session, @TvInteractiveAppManager.InteractiveAppState int state, @TvInteractiveAppManager.ErrorCode int err)1522 public void onSessionStateChanged( 1523 Session session, 1524 @TvInteractiveAppManager.InteractiveAppState int state, 1525 @TvInteractiveAppManager.ErrorCode int err) { 1526 if (DEBUG) { 1527 Log.d(TAG, "onSessionStateChanged (state=" + state + "; err=" + err + ")"); 1528 } 1529 if (this != mSessionCallback) { 1530 Log.w(TAG, "onSessionStateChanged - session not created"); 1531 return; 1532 } 1533 synchronized (mCallbackLock) { 1534 if (mCallbackExecutor != null) { 1535 mCallbackExecutor.execute(() -> { 1536 synchronized (mCallbackLock) { 1537 if (mCallback != null) { 1538 mCallback.onStateChanged(mIAppServiceId, state, err); 1539 } 1540 } 1541 }); 1542 } 1543 } 1544 } 1545 1546 @Override onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId)1547 public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) { 1548 if (DEBUG) { 1549 Log.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri + ", biIAppId=" 1550 + biIAppId + ")"); 1551 } 1552 if (this != mSessionCallback) { 1553 Log.w(TAG, "onBiInteractiveAppCreated - session not created"); 1554 return; 1555 } 1556 synchronized (mCallbackLock) { 1557 if (mCallbackExecutor != null) { 1558 mCallbackExecutor.execute(() -> { 1559 synchronized (mCallbackLock) { 1560 if (mCallback != null) { 1561 mCallback.onBiInteractiveAppCreated( 1562 mIAppServiceId, biIAppUri, biIAppId); 1563 } 1564 } 1565 }); 1566 } 1567 } 1568 } 1569 1570 @Override onTeletextAppStateChanged(Session session, int state)1571 public void onTeletextAppStateChanged(Session session, int state) { 1572 if (DEBUG) { 1573 Log.d(TAG, "onTeletextAppStateChanged (state=" + state + ")"); 1574 } 1575 if (this != mSessionCallback) { 1576 Log.w(TAG, "onTeletextAppStateChanged - session not created"); 1577 return; 1578 } 1579 if (mCallback != null) { 1580 mCallback.onTeletextAppStateChanged(mIAppServiceId, state); 1581 } 1582 } 1583 1584 @Override onSetVideoBounds(Session session, Rect rect)1585 public void onSetVideoBounds(Session session, Rect rect) { 1586 if (DEBUG) { 1587 Log.d(TAG, "onSetVideoBounds (rect=" + rect + ")"); 1588 } 1589 if (this != mSessionCallback) { 1590 Log.w(TAG, "onSetVideoBounds - session not created"); 1591 return; 1592 } 1593 synchronized (mCallbackLock) { 1594 if (mCallbackExecutor != null) { 1595 mCallbackExecutor.execute(() -> { 1596 synchronized (mCallbackLock) { 1597 if (mCallback != null) { 1598 mCallback.onSetVideoBounds(mIAppServiceId, rect); 1599 } 1600 } 1601 }); 1602 } 1603 } 1604 } 1605 1606 @Override onRequestCurrentVideoBounds(Session session)1607 public void onRequestCurrentVideoBounds(Session session) { 1608 if (DEBUG) { 1609 Log.d(TAG, "onRequestCurrentVideoBounds"); 1610 } 1611 if (this != mSessionCallback) { 1612 Log.w(TAG, "onRequestCurrentVideoBounds - session not created"); 1613 return; 1614 } 1615 synchronized (mCallbackLock) { 1616 if (mCallbackExecutor != null) { 1617 mCallbackExecutor.execute(() -> { 1618 synchronized (mCallbackLock) { 1619 if (mCallback != null) { 1620 mCallback.onRequestCurrentVideoBounds(mIAppServiceId); 1621 } 1622 } 1623 }); 1624 } 1625 } 1626 } 1627 1628 @Override onRequestCurrentChannelUri(Session session)1629 public void onRequestCurrentChannelUri(Session session) { 1630 if (DEBUG) { 1631 Log.d(TAG, "onRequestCurrentChannelUri"); 1632 } 1633 if (this != mSessionCallback) { 1634 Log.w(TAG, "onRequestCurrentChannelUri - session not created"); 1635 return; 1636 } 1637 synchronized (mCallbackLock) { 1638 if (mCallbackExecutor != null) { 1639 mCallbackExecutor.execute(() -> { 1640 synchronized (mCallbackLock) { 1641 if (mCallback != null) { 1642 mCallback.onRequestCurrentChannelUri(mIAppServiceId); 1643 } 1644 } 1645 }); 1646 } 1647 } 1648 } 1649 1650 @Override onRequestCurrentChannelLcn(Session session)1651 public void onRequestCurrentChannelLcn(Session session) { 1652 if (DEBUG) { 1653 Log.d(TAG, "onRequestCurrentChannelLcn"); 1654 } 1655 if (this != mSessionCallback) { 1656 Log.w(TAG, "onRequestCurrentChannelLcn - session not created"); 1657 return; 1658 } 1659 synchronized (mCallbackLock) { 1660 if (mCallbackExecutor != null) { 1661 mCallbackExecutor.execute(() -> { 1662 synchronized (mCallbackLock) { 1663 if (mCallback != null) { 1664 mCallback.onRequestCurrentChannelLcn(mIAppServiceId); 1665 } 1666 } 1667 }); 1668 } 1669 } 1670 } 1671 1672 @Override onRequestStreamVolume(Session session)1673 public void onRequestStreamVolume(Session session) { 1674 if (DEBUG) { 1675 Log.d(TAG, "onRequestStreamVolume"); 1676 } 1677 if (this != mSessionCallback) { 1678 Log.w(TAG, "onRequestStreamVolume - session not created"); 1679 return; 1680 } 1681 synchronized (mCallbackLock) { 1682 if (mCallbackExecutor != null) { 1683 mCallbackExecutor.execute(() -> { 1684 synchronized (mCallbackLock) { 1685 if (mCallback != null) { 1686 mCallback.onRequestStreamVolume(mIAppServiceId); 1687 } 1688 } 1689 }); 1690 } 1691 } 1692 } 1693 1694 @Override onRequestTrackInfoList(Session session)1695 public void onRequestTrackInfoList(Session session) { 1696 if (DEBUG) { 1697 Log.d(TAG, "onRequestTrackInfoList"); 1698 } 1699 if (this != mSessionCallback) { 1700 Log.w(TAG, "onRequestTrackInfoList - session not created"); 1701 return; 1702 } 1703 synchronized (mCallbackLock) { 1704 if (mCallbackExecutor != null) { 1705 mCallbackExecutor.execute(() -> { 1706 synchronized (mCallbackLock) { 1707 if (mCallback != null) { 1708 mCallback.onRequestTrackInfoList(mIAppServiceId); 1709 } 1710 } 1711 }); 1712 } 1713 } 1714 } 1715 1716 @Override onRequestCurrentTvInputId(Session session)1717 public void onRequestCurrentTvInputId(Session session) { 1718 if (DEBUG) { 1719 Log.d(TAG, "onRequestCurrentTvInputId"); 1720 } 1721 if (this != mSessionCallback) { 1722 Log.w(TAG, "onRequestCurrentTvInputId - session not created"); 1723 return; 1724 } 1725 if (mCallback != null) { 1726 mCallback.onRequestCurrentTvInputId(mIAppServiceId); 1727 } 1728 } 1729 1730 @Override onRequestTimeShiftMode(Session session)1731 public void onRequestTimeShiftMode(Session session) { 1732 if (DEBUG) { 1733 Log.d(TAG, "onRequestTimeShiftMode"); 1734 } 1735 if (this != mSessionCallback) { 1736 Log.w(TAG, "onRequestTimeShiftMode - session not created"); 1737 return; 1738 } 1739 if (mCallback != null) { 1740 mCallback.onRequestTimeShiftMode(mIAppServiceId); 1741 } 1742 } 1743 1744 @Override onRequestAvailableSpeeds(Session session)1745 public void onRequestAvailableSpeeds(Session session) { 1746 if (DEBUG) { 1747 Log.d(TAG, "onRequestAvailableSpeeds"); 1748 } 1749 if (this != mSessionCallback) { 1750 Log.w(TAG, "onRequestAvailableSpeeds - session not created"); 1751 return; 1752 } 1753 if (mCallback != null) { 1754 mCallback.onRequestAvailableSpeeds(mIAppServiceId); 1755 } 1756 } 1757 1758 @Override onRequestStartRecording(Session session, String requestId, Uri programUri)1759 public void onRequestStartRecording(Session session, String requestId, Uri programUri) { 1760 if (DEBUG) { 1761 Log.d(TAG, "onRequestStartRecording"); 1762 } 1763 if (this != mSessionCallback) { 1764 Log.w(TAG, "onRequestStartRecording - session not created"); 1765 return; 1766 } 1767 if (mCallback != null) { 1768 mCallback.onRequestStartRecording(mIAppServiceId, requestId, programUri); 1769 } 1770 } 1771 1772 @Override onRequestStopRecording(Session session, String recordingId)1773 public void onRequestStopRecording(Session session, String recordingId) { 1774 if (DEBUG) { 1775 Log.d(TAG, "onRequestStopRecording"); 1776 } 1777 if (this != mSessionCallback) { 1778 Log.w(TAG, "onRequestStopRecording - session not created"); 1779 return; 1780 } 1781 if (mCallback != null) { 1782 mCallback.onRequestStopRecording(mIAppServiceId, recordingId); 1783 } 1784 } 1785 1786 @Override onSetTvRecordingInfo( Session session, String recordingId, TvRecordingInfo recordingInfo)1787 public void onSetTvRecordingInfo( 1788 Session session, String recordingId, TvRecordingInfo recordingInfo) { 1789 if (DEBUG) { 1790 Log.d(TAG, "onSetRecordingInfo"); 1791 } 1792 if (this != mSessionCallback) { 1793 Log.w(TAG, "onSetRecordingInfo - session not created"); 1794 return; 1795 } 1796 if (mCallback != null) { 1797 mCallback.onSetTvRecordingInfo(mIAppServiceId, recordingId, recordingInfo); 1798 } 1799 } 1800 1801 @Override onRequestScheduleRecording(Session session, @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, Uri programUri, @NonNull Bundle params)1802 public void onRequestScheduleRecording(Session session, @NonNull String requestId, 1803 @NonNull String inputId, @NonNull Uri channelUri, Uri programUri, 1804 @NonNull Bundle params) { 1805 if (DEBUG) { 1806 Log.d(TAG, "onRequestScheduleRecording"); 1807 } 1808 if (this != mSessionCallback) { 1809 Log.w(TAG, "onRequestScheduleRecording - session not created"); 1810 return; 1811 } 1812 if (mCallback != null) { 1813 mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri, 1814 programUri, params); 1815 } 1816 } 1817 onRequestScheduleRecording(Session session, @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration, int repeatDays, @NonNull Bundle params)1818 public void onRequestScheduleRecording(Session session, @NonNull String requestId, 1819 @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration, 1820 int repeatDays, @NonNull Bundle params) { 1821 if (DEBUG) { 1822 Log.d(TAG, "onRequestScheduleRecording"); 1823 } 1824 if (this != mSessionCallback) { 1825 Log.w(TAG, "onRequestScheduleRecording - session not created"); 1826 return; 1827 } 1828 if (mCallback != null) { 1829 mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri, 1830 startTime, duration, repeatDays, params); 1831 } 1832 } 1833 1834 @Override onRequestTvRecordingInfo(Session session, String recordingId)1835 public void onRequestTvRecordingInfo(Session session, 1836 String recordingId) { 1837 if (DEBUG) { 1838 Log.d(TAG, "onRequestRecordingInfo"); 1839 } 1840 if (this != mSessionCallback) { 1841 Log.w(TAG, "onRequestRecordingInfo - session not created"); 1842 return; 1843 } 1844 if (mCallback != null) { 1845 mCallback.onRequestTvRecordingInfo(mIAppServiceId, recordingId); 1846 } 1847 } 1848 1849 @Override onRequestTvRecordingInfoList(Session session, int type)1850 public void onRequestTvRecordingInfoList(Session session, 1851 int type) { 1852 if (DEBUG) { 1853 Log.d(TAG, "onRequestRecordingInfoList"); 1854 } 1855 if (this != mSessionCallback) { 1856 Log.w(TAG, "onRequestRecordingInfoList - session not created"); 1857 return; 1858 } 1859 if (mCallback != null) { 1860 mCallback.onRequestTvRecordingInfoList(mIAppServiceId, type); 1861 } 1862 } 1863 1864 @Override onRequestSigning( Session session, String id, String algorithm, String alias, byte[] data)1865 public void onRequestSigning( 1866 Session session, String id, String algorithm, String alias, byte[] data) { 1867 if (DEBUG) { 1868 Log.d(TAG, "onRequestSigning"); 1869 } 1870 if (this != mSessionCallback) { 1871 Log.w(TAG, "onRequestSigning - session not created"); 1872 return; 1873 } 1874 if (mCallback != null) { 1875 mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data); 1876 } 1877 } 1878 } 1879 } 1880