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