19a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho/*
29a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * Copyright (C) 2014 The Android Open Source Project
39a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho *
49a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * Licensed under the Apache License, Version 2.0 (the "License");
59a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * you may not use this file except in compliance with the License.
69a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * You may obtain a copy of the License at
79a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho *
89a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho *      http://www.apache.org/licenses/LICENSE-2.0
99a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho *
109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * Unless required by applicable law or agreed to in writing, software
119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * distributed under the License is distributed on an "AS IS" BASIS,
129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * See the License for the specific language governing permissions and
149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * limitations under the License.
159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */
169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
17d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seopackage android.media.tv;
189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
19cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seoimport android.annotation.FloatRange;
20c8b7356434f665c494504661a943323c0bbe702eJae Seoimport android.annotation.NonNull;
214bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kangimport android.annotation.Nullable;
22e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kangimport android.annotation.RequiresPermission;
23a759b111a1c9cb00284038f8a1554bf29709b952Jae Seoimport android.annotation.SystemApi;
249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.content.Context;
255f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kangimport android.graphics.Canvas;
265f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kangimport android.graphics.PorterDuff;
279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
285f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kangimport android.graphics.Region;
293d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seoimport android.media.PlaybackParams;
30d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.Session;
31d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
32d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.SessionCallback;
33b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seoimport android.net.Uri;
34832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.os.Handler;
36d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Limimport android.text.TextUtils;
379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.AttributeSet;
389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Log;
39411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport android.util.Pair;
406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEvent;
416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.KeyEvent;
426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.MotionEvent;
439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.Surface;
449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.SurfaceHolder;
459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.SurfaceView;
4607b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Choimport android.view.View;
471bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seoimport android.view.ViewGroup;
48c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Leeimport android.view.ViewRootImpl;
499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
50c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Leeimport java.lang.ref.WeakReference;
51411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport java.util.ArrayDeque;
521f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport java.util.List;
53411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport java.util.Queue;
541f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho/**
569551e92507564c597a7764473945114d3c3bfff3Jae Seo * Displays TV contents. The TvView class provides a high level interface for applications to show
579551e92507564c597a7764473945114d3c3bfff3Jae Seo * TV programs from various TV sources that implement {@link TvInputService}. (Note that the list of
589551e92507564c597a7764473945114d3c3bfff3Jae Seo * TV inputs available on the system can be obtained by calling
599551e92507564c597a7764473945114d3c3bfff3Jae Seo * {@link TvInputManager#getTvInputList() TvInputManager.getTvInputList()}.)
600610e12733875a267f59d87a2a68aebbf486066eDongwon Kang *
61e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * <p>Once the application supplies the URI for a specific TV channel to {@link #tune}
629551e92507564c597a7764473945114d3c3bfff3Jae Seo * method, it takes care of underlying service binding (and unbinding if the current TvView is
639551e92507564c597a7764473945114d3c3bfff3Jae Seo * already bound to a service) and automatically allocates/deallocates resources needed. In addition
649551e92507564c597a7764473945114d3c3bfff3Jae Seo * to a few essential methods to control how the contents are presented, it also provides a way to
659551e92507564c597a7764473945114d3c3bfff3Jae Seo * dispatch input events to the connected TvInputService in order to enable custom key actions for
669551e92507564c597a7764473945114d3c3bfff3Jae Seo * the TV input.
679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */
681bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seopublic class TvView extends ViewGroup {
69b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    private static final String TAG = "TvView";
70ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo    private static final boolean DEBUG = false;
71b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
72bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_MEDIA = 0;
73bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_MEDIA_OVERLAY = 1;
74bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_ON_TOP = 2;
75bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    private static final WeakReference<TvView> NULL_TV_VIEW = new WeakReference<>(null);
77c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee
784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private static final Object sMainTvViewLock = new Object();
79c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee    private static WeakReference<TvView> sMainTvView = NULL_TV_VIEW;
804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private final Handler mHandler = new Handler();
82903d6b72cd572665309633e925485464d08bb25aJaewan Kim    private Session mSession;
8371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private SurfaceView mSurfaceView;
849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Surface mSurface;
859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private boolean mOverlayViewCreated;
869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Rect mOverlayViewFrame;
876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final TvInputManager mTvInputManager;
88b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    private MySessionCallback mSessionCallback;
892778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private TvInputCallback mCallback;
906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
911da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo    private Float mStreamVolume;
921da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo    private Boolean mCaptionEnabled;
93411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo    private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
94887f52144eeea8d5812d64a29e207af6b97a763dJae Seo
95e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private boolean mSurfaceChanged;
96e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceFormat;
97e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceWidth;
98e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceHeight;
9971b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private final AttributeSet mAttrs;
10071b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private final int mDefStyleAttr;
101bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private int mWindowZOrder;
102ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private boolean mUseRequestedSurfaceLayout;
103ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewLeft;
104ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewRight;
105ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewTop;
106ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewBottom;
107465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    private TimeShiftPositionCallback mTimeShiftPositionCallback;
1089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
1109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
11215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
11315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width="
11415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    + width + ", height=" + height + ")");
11515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
116e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceFormat = format;
117e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceWidth = width;
118e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceHeight = height;
119e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceChanged = true;
120e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
1219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceCreated(SurfaceHolder holder) {
1259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSurface = holder.getSurface();
1269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            setSessionSurface(mSurface);
1279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceDestroyed(SurfaceHolder holder) {
1319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSurface = null;
132e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceChanged = false;
1339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            setSessionSurface(null);
1349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    };
1369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final FinishedInputEventCallback mFinishedInputEventCallback =
1386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            new FinishedInputEventCallback() {
1396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        @Override
1406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public void onFinishedInputEvent(Object token, boolean handled) {
1416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (DEBUG) {
1426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" + handled + ")");
1436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
1446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (handled) {
1456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return;
1466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
1476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            // TODO: Re-order unhandled events.
1486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            InputEvent event = (InputEvent) token;
1496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (dispatchUnhandledInputEvent(event)) {
1506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return;
1516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
152c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            ViewRootImpl viewRootImpl = getViewRootImpl();
153c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            if (viewRootImpl != null) {
154c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee                viewRootImpl.dispatchUnhandledInputEvent(event);
155c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            }
1566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
1576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    };
1586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
1599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context) {
1609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        this(context, null, 0);
1619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context, AttributeSet attrs) {
1649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        this(context, attrs, 0);
1659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context, AttributeSet attrs, int defStyleAttr) {
1689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super(context, attrs, defStyleAttr);
16971b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mAttrs = attrs;
17071b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mDefStyleAttr = defStyleAttr;
17171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        resetSurfaceView();
1729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
1739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    /**
1762778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Sets the callback to be invoked when an event is dispatched to this TvView.
1779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho     *
178465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param callback The callback to receive events. A value of {@code null} removes the existing
179465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     *            callback.
1809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho     */
1814bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang    public void setCallback(@Nullable TvInputCallback callback) {
1822778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        mCallback = callback;
1839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
18615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * Sets this as the main {@link TvView}.
1870610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
1880610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>The main {@link TvView} is a {@link TvView} whose corresponding TV input determines the
18915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * HDMI-CEC active source device. For an HDMI port input, one of source devices that is
19015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * connected to that HDMI port becomes the active source. For an HDMI-CEC logical device input,
19115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * the corresponding HDMI-CEC logical device becomes the active source. For any non-HDMI input
19215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * (including the tuner, composite, S-Video, etc.), the internal device (= TV itself) becomes
19315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * the active source.
1940610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
1950610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>First tuned {@link TvView} becomes main automatically, and keeps to be main until either
1966e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo     * {@link #reset} is called for the main {@link TvView} or {@code setMain()} is called for other
197c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee     * {@link TvView}.
1984c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee     * @hide
1994c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee     */
2004c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    @SystemApi
20115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    public void setMain() {
2024c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
2036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            sMainTvView = new WeakReference<>(this);
2044c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            if (hasWindowFocus() && mSession != null) {
20515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                mSession.setMain();
2064c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
2074c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
2084c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
2094c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
2104c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    /**
211e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Controls whether the TvView's surface is placed on top of another regular surface view in the
212e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * window (but still behind the window itself).
213e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * This is typically used to place overlays on top of an underlying TvView.
214bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     *
215e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Note that this must be set before the TvView's containing window is attached to the
216e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * window manager.
217e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
218e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
219e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
220e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
221e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            otherwise.
222bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     */
223bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    public void setZOrderMediaOverlay(boolean isMediaOverlay) {
224bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (isMediaOverlay) {
225bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA_OVERLAY;
226bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            removeSessionOverlayView();
227bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else {
228bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA;
229bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            createSessionOverlayView();
230bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
231bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSurfaceView != null) {
232bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            // ZOrderOnTop(false) removes WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
233bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            // from WindowLayoutParam as well as changes window type.
234bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(false);
235bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
236bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
237bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    }
238bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
239bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    /**
240e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Controls whether the TvView's surface is placed on top of its window. Normally it is placed
241e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * behind the window, to allow it to (for the most part) appear to composite with the views in
242e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * the hierarchy.  By setting this, you cause it to be placed above the window. This means that
243e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * none of the contents of the window this TvView is in will be visible on top of its surface.
244bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     *
245e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Note that this must be set before the TvView's containing window is attached to the window
246e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * manager.
247e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
248e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
249e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
250e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
251bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     */
252bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    public void setZOrderOnTop(boolean onTop) {
253bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (onTop) {
254bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_ON_TOP;
255bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            removeSessionOverlayView();
256bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else {
257bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA;
258bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            createSessionOverlayView();
259bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
260bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSurfaceView != null) {
261bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(false);
262bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(onTop);
263bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
264bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     }
265bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
266bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    /**
2671da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * Sets the relative stream volume of this TvView.
2681da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     *
2691da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * <p>This method is primarily used to handle audio focus changes or mute a specific TvView when
2701da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * multiple views are displayed. If the method has not yet been called, the TvView assumes the
2711da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * default value of {@code 1.0f}.
272782f7345471072b630e58c7abd3579b0015273b1Jae Seo     *
2731da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
274782f7345471072b630e58c7abd3579b0015273b1Jae Seo     */
275cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public void setStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {
276782f7345471072b630e58c7abd3579b0015273b1Jae Seo        if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
277336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang        mStreamVolume = volume;
278782f7345471072b630e58c7abd3579b0015273b1Jae Seo        if (mSession == null) {
279336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang            // Volume will be set once the connection has been made.
280782f7345471072b630e58c7abd3579b0015273b1Jae Seo            return;
281782f7345471072b630e58c7abd3579b0015273b1Jae Seo        }
282782f7345471072b630e58c7abd3579b0015273b1Jae Seo        mSession.setStreamVolume(volume);
283782f7345471072b630e58c7abd3579b0015273b1Jae Seo    }
284782f7345471072b630e58c7abd3579b0015273b1Jae Seo
285782f7345471072b630e58c7abd3579b0015273b1Jae Seo    /**
286b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * Tunes to a given channel.
287b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     *
288b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo     * @param inputId The ID of the TV input for the given channel.
289b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @param channelUri The URI of a channel.
290b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
291c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void tune(@NonNull String inputId, Uri channelUri) {
2921a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        tune(inputId, channelUri, null);
2931a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    }
2941a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
2951a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    /**
296e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Tunes to a given channel. This can be used to provide domain-specific features that are only
297f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * known between certain clients and their TV inputs.
2981a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     *
299b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo     * @param inputId The ID of TV input for the given channel.
3001a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     * @param channelUri The URI of a channel.
301e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
302e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            name, i.e. prefixed with a package name you own, so that different developers will
303e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            not create conflicting keys.
3041a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     */
3051a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    public void tune(String inputId, Uri channelUri, Bundle params) {
306b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
307b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (TextUtils.isEmpty(inputId)) {
308b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            throw new IllegalArgumentException("inputId cannot be null or an empty string");
309b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
3104c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
311c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (sMainTvView.get() == null) {
3126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                sMainTvView = new WeakReference<>(this);
3134c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
3144c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
315b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
316b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            if (mSession != null) {
3171a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mSession.tune(channelUri, params);
318b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            } else {
319b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // createSession() was called but the actual session for the given inputId has not
320b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // yet been created. Just replace the existing tuning params in the callback with
321b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // the new ones and tune later in onSessionCreated(). It is not necessary to create
322b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // a new callback because this tuning request was made on the same inputId.
323b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo                mSessionCallback.mChannelUri = channelUri;
3241a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mSessionCallback.mTuneParams = params;
325b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            }
326b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        } else {
327d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee            resetInternal();
328b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // In case createSession() is called multiple times across different inputId's before
329b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // any session is created (e.g. when quickly tuning to a channel from input A and then
330b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // to another channel from input B), only the callback for the last createSession()
331b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // should be invoked. (The previous callbacks are simply ignored.) To do that, we create
332b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // a new callback each time and keep mSessionCallback pointing to the last one. If
333b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // MySessionCallback.this is different from mSessionCallback, we know that this callback
334b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // is obsolete and should ignore it.
3351a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            mSessionCallback = new MySessionCallback(inputId, channelUri, params);
3369127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            if (mTvInputManager != null) {
3379127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
3389127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            }
339b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
340b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
341b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
342b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
343b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * Resets this TvView.
3440610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
3450610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>This method is primarily used to un-tune the current TvView.
346b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
347b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    public void reset() {
34815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (DEBUG) Log.d(TAG, "reset()");
349c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee        synchronized (sMainTvViewLock) {
350c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (this == sMainTvView.get()) {
351c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee                sMainTvView = NULL_TV_VIEW;
352c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            }
353c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee        }
354d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee        resetInternal();
355d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee    }
356d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee
357d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee    private void resetInternal() {
358b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo        mSessionCallback = null;
35917345072864b9aeb4e5535257e83e6809859ae0fJae Seo        mPendingAppPrivateCommands.clear();
360b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (mSession != null) {
36117345072864b9aeb4e5535257e83e6809859ae0fJae Seo            setSessionSurface(null);
36217345072864b9aeb4e5535257e83e6809859ae0fJae Seo            removeSessionOverlayView();
36317345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mUseRequestedSurfaceLayout = false;
36417345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mSession.release();
36517345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mSession = null;
36671b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            resetSurfaceView();
367b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
368b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
369b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
370b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
3719bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim     * Requests to unblock TV content according to the given rating.
3720610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
3730610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>This notifies TV input that blocked content is now OK to play.
374903d6b72cd572665309633e925485464d08bb25aJaewan Kim     *
3759bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim     * @param unblockedRating A TvContentRating to unblock.
37691a801d42f3acc35404da51ba26605093922503aJae Seo     * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
377e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @removed
378903d6b72cd572665309633e925485464d08bb25aJaewan Kim     */
3799bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim    public void requestUnblockContent(TvContentRating unblockedRating) {
380a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo        unblockContent(unblockedRating);
381a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    }
382a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo
383a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    /**
384a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * Requests to unblock TV content according to the given rating.
385a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     *
386a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * <p>This notifies TV input that blocked content is now OK to play.
387a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     *
388a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @param unblockedRating A TvContentRating to unblock.
389a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
390a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @hide
391a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     */
392a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    @SystemApi
393e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
394a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    public void unblockContent(TvContentRating unblockedRating) {
395903d6b72cd572665309633e925485464d08bb25aJaewan Kim        if (mSession != null) {
396a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo            mSession.unblockContent(unblockedRating);
397903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
398903d6b72cd572665309633e925485464d08bb25aJaewan Kim    }
399903d6b72cd572665309633e925485464d08bb25aJaewan Kim
400903d6b72cd572665309633e925485464d08bb25aJaewan Kim    /**
4012c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     * Enables or disables the caption in this TvView.
4020610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
4030610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Note that this method does not take any effect unless the current TvView is tuned.
4042c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     *
4052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     * @param enabled {@code true} to enable, {@code false} to disable.
4062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     */
4072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    public void setCaptionEnabled(boolean enabled) {
4081da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo        if (DEBUG) Log.d(TAG, "setCaptionEnabled(" + enabled + ")");
4091da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo        mCaptionEnabled = enabled;
4102c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        if (mSession != null) {
4112c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            mSession.setCaptionEnabled(enabled);
4122c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
4132c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    }
4142c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
4152c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    /**
4161f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Selects a track.
4172c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     *
41810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the track to select. The type can be {@link TvTrackInfo#TYPE_AUDIO},
41910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
42010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param trackId The ID of the track to select. {@code null} means to unselect the current
42110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            track for a given type.
42210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getTracks
42310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getSelectedTrack
4241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     */
42510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public void selectTrack(int type, String trackId) {
4261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        if (mSession != null) {
42710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            mSession.selectTrack(type, trackId);
4281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
4291f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    }
4301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
4311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    /**
43210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * Returns the list of tracks. Returns {@code null} if the information is not available.
4331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     *
43410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
43510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
43610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #selectTrack
43710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getSelectedTrack
4381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     */
43910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public List<TvTrackInfo> getTracks(int type) {
4401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        if (mSession == null) {
4411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            return null;
4421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
44310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        return mSession.getTracks(type);
4441f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    }
4451f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
4461f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    /**
44710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * Returns the ID of the selected track for a given type. Returns {@code null} if the
44810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * information is not available or the track is not selected.
44910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *
45010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the selected tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
45110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
45210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #selectTrack
45310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getTracks
454d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo     */
45510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public String getSelectedTrack(int type) {
456d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        if (mSession == null) {
457d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            return null;
458d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
45910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        return mSession.getSelectedTrack(type);
460d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo    }
461d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
462d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo    /**
463a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * Plays a given recorded TV program.
464a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     *
465a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input that created the given recorded program.
466a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param recordedProgramUri The URI of a recorded program.
467a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     */
468a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    public void timeShiftPlay(String inputId, Uri recordedProgramUri) {
469a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (DEBUG) Log.d(TAG, "timeShiftPlay(" + recordedProgramUri + ")");
470a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (TextUtils.isEmpty(inputId)) {
471a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            throw new IllegalArgumentException("inputId cannot be null or an empty string");
472a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
473a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        synchronized (sMainTvViewLock) {
474a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (sMainTvView.get() == null) {
475a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                sMainTvView = new WeakReference<>(this);
476a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
477a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
478a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
479a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mSession != null) {
480a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mSession.timeShiftPlay(recordedProgramUri);
481a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            } else {
482a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mSessionCallback.mRecordedProgramUri = recordedProgramUri;
483a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
484a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        } else {
485a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            resetInternal();
486a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mSessionCallback = new MySessionCallback(inputId, recordedProgramUri);
487a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mTvInputManager != null) {
488a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
489a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
490a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
491a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    }
492a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
493a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /**
494465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Pauses playback. No-op if it is already paused. Call {@link #timeShiftResume} to resume.
4956f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
4966f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftPause() {
4976f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
4986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftPause();
4996f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5006f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5026f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
503465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Resumes playback. No-op if it is already resumed. Call {@link #timeShiftPause} to pause.
5046f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftResume() {
5066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftResume();
5086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
512465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Seeks to a specified time position. {@code timeMs} must be equal to or greater than the start
513465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * position returned by {@link TimeShiftPositionCallback#onTimeShiftStartPositionChanged} and
514465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * equal to or less than the current time.
5156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
516465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param timeMs The time position to seek to, in milliseconds since the epoch.
5176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5186f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftSeekTo(long timeMs) {
5196f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftSeekTo(timeMs);
5216f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5226f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5236f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5246f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
5254b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo     * Sets playback rate using {@link android.media.PlaybackParams}.
5266f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
5273d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo     * @param params The playback params.
5286f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5293d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo    public void timeShiftSetPlaybackParams(@NonNull PlaybackParams params) {
5306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5314b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo            mSession.timeShiftSetPlaybackParams(params);
5326f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5336f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5346f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
536465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Sets the callback to be invoked when the time shift position is changed.
5376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
538465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param callback The callback to receive time shift position changes. A value of {@code null}
539465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     *            removes the existing callback.
5406f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5414bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang    public void setTimeShiftPositionCallback(@Nullable TimeShiftPositionCallback callback) {
542465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        mTimeShiftPositionCallback = callback;
543465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        ensurePositionTracking();
5446f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
546465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    private void ensurePositionTracking() {
5476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession == null) {
5486f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            return;
5496f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
550465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        mSession.timeShiftEnablePositionTracking(mTimeShiftPositionCallback != null);
5516f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
554f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * Sends a private command to the underlying TV input. This can be used to provide
555f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * domain-specific features that are only known between certain clients and their TV inputs.
556a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo     *
557887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     * @param action The name of the private command to send. This <em>must</em> be a scoped name,
558887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     *            i.e. prefixed with a package name you own, so that different developers will not
559887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     *            create conflicting commands.
560887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     * @param data An optional bundle to send with the command.
561a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo     */
562c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void sendAppPrivateCommand(@NonNull String action, Bundle data) {
563a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        if (TextUtils.isEmpty(action)) {
564a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            throw new IllegalArgumentException("action cannot be null or an empty string");
565a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
566a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        if (mSession != null) {
567a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            mSession.sendAppPrivateCommand(action, data);
568887f52144eeea8d5812d64a29e207af6b97a763dJae Seo        } else {
569411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo            Log.w(TAG, "sendAppPrivateCommand - session not yet created (action \"" + action
570411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                    + "\" pending)");
571411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo            mPendingAppPrivateCommands.add(Pair.create(action, data));
572a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
573a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo    }
574a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
575a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo    /**
5766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * Dispatches an unhandled input event to the next receiver.
5770610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
5780610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Except system keys, TvView always consumes input events in the normal flow. This is called
5796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * asynchronously from where the event is dispatched. It gives the host application a chance to
5806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * dispatch the unhandled input events.
5816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
5826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @param event The input event.
5836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @return {@code true} if the event was handled by the view, {@code false} otherwise.
5846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
5856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchUnhandledInputEvent(InputEvent event) {
5866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mOnUnhandledInputEventListener != null) {
5876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) {
5886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return true;
5896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
5906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
5916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return onUnhandledInputEvent(event);
5926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
5936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
5946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
5951f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Called when an unhandled input event also has not been handled by the user provided
5961f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * callback. This is the last chance to handle the unhandled input event in the TvView.
5976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
5986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @param event The input event.
5996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @return If you handled the event, return {@code true}. If you want to allow the event to be
6006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *         handled by the next receiver, return {@code false}.
6016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
6026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean onUnhandledInputEvent(InputEvent event) {
6036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return false;
6046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
6071f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Registers a callback to be invoked when an input event is not handled by the bound TV input.
6086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
6091f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * @param listener The callback to be invoked when the unhandled input event is received.
6106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
6116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) {
6126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        mOnUnhandledInputEventListener = listener;
6136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchKeyEvent(KeyEvent event) {
6176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchKeyEvent(event)) {
6186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")");
6216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
624f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
625f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
626f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchTouchEvent(MotionEvent event) {
6326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchTouchEvent(event)) {
6336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchTouchEvent(" + event + ")");
6366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
639f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
640f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
641f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchTrackballEvent(MotionEvent event) {
6476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchTrackballEvent(event)) {
6486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchTrackballEvent(" + event + ")");
6516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
654f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
655f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
656f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchGenericMotionEvent(MotionEvent event) {
6626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchGenericMotionEvent(event)) {
6636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent(" + event + ")");
6666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
669f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
670f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
671f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
6764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    public void dispatchWindowFocusChanged(boolean hasFocus) {
6774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        super.dispatchWindowFocusChanged(hasFocus);
6784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // Other app may have shown its own main TvView.
6794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // Set main again to regain main session.
6804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
681c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (hasFocus && this == sMainTvView.get() && mSession != null) {
68215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                mSession.setMain();
6834c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
6844c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
6854c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
6864c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
6874c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    @Override
6889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    protected void onAttachedToWindow() {
6899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super.onAttachedToWindow();
6909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        createSessionOverlayView();
6919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
6929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
6939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
6949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    protected void onDetachedFromWindow() {
6959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        removeSessionOverlayView();
6969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super.onDetachedFromWindow();
6979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
6989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
6999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
7001bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
701ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        if (DEBUG) {
702ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            Log.d(TAG, "onLayout (left=" + left + ", top=" + top + ", right=" + right
703ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    + ", bottom=" + bottom + ",)");
704ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
705ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        if (mUseRequestedSurfaceLayout) {
706ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceView.layout(mSurfaceViewLeft, mSurfaceViewTop, mSurfaceViewRight,
707ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    mSurfaceViewBottom);
708ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        } else {
709ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceView.layout(0, 0, right - left, bottom - top);
710ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
7111bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    }
7121bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo
7131bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    @Override
7141bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
7151bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec);
7161bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int width = mSurfaceView.getMeasuredWidth();
7171bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int height = mSurfaceView.getMeasuredHeight();
7181bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int childState = mSurfaceView.getMeasuredState();
7191bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
7201bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo                resolveSizeAndState(height, heightMeasureSpec,
7211bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo                        childState << MEASURED_HEIGHT_STATE_SHIFT));
7221bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    }
7231bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo
7241bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    @Override
7255f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    public boolean gatherTransparentRegion(Region region) {
7265f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7275f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            if (region != null) {
7285f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                int width = getWidth();
7295f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                int height = getHeight();
7305f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                if (width > 0 && height > 0) {
7315f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int location[] = new int[2];
7325f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    getLocationInWindow(location);
7335f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int left = location[0];
7345f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int top = location[1];
7355f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    region.op(left, top, left + width, top + height, Region.Op.UNION);
7365f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                }
7375f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            }
7385f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7395f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        return super.gatherTransparentRegion(region);
7405f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7415f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7425f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7435f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    public void draw(Canvas canvas) {
7445f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7455f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            // Punch a hole so that the underlying overlay view and surface can be shown.
7465f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
7475f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7485f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        super.draw(canvas);
7495f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7505f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7515f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7525f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    protected void dispatchDraw(Canvas canvas) {
7535f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7545f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            // Punch a hole so that the underlying overlay view and surface can be shown.
7555f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
7565f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7575f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        super.dispatchDraw(canvas);
7585f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7595f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7605f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7616a1f2649a917ddec808e75f31efeb227133dd096Christofer Ã…kersten    protected void onVisibilityChanged(View changedView, int visibility) {
7626a1f2649a917ddec808e75f31efeb227133dd096Christofer Ã…kersten        super.onVisibilityChanged(changedView, visibility);
7631bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        mSurfaceView.setVisibility(visibility);
76407b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        if (visibility == View.VISIBLE) {
76507b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho            createSessionOverlayView();
76607b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        } else {
76707b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho            removeSessionOverlayView();
76807b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        }
7699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
7709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
77171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private void resetSurfaceView() {
77271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        if (mSurfaceView != null) {
77371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
77471b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            removeView(mSurfaceView);
77571b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        }
77615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        mSurface = null;
77771b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
77871b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            @Override
77971b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            protected void updateWindow(boolean force, boolean redrawNeeded) {
78071b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho                super.updateWindow(force, redrawNeeded);
78171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho                relayoutSessionOverlayView();
78271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            }};
78322168a7dfccab1865bc43b4c43a340b27deee9bbJae Seo        // The surface view's content should be treated as secure all the time.
78422168a7dfccab1865bc43b4c43a340b27deee9bbJae Seo        mSurfaceView.setSecure(true);
78571b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
786bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mWindowZOrder == ZORDER_MEDIA_OVERLAY) {
787bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(true);
788bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else if (mWindowZOrder == ZORDER_ON_TOP) {
789bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(true);
790bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
79171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        addView(mSurfaceView);
79271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    }
79371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho
7949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void setSessionSurface(Surface surface) {
7959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null) {
7969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
7979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
7989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.setSurface(surface);
7999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
801e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private void dispatchSurfaceChanged(int format, int width, int height) {
802e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        if (mSession == null) {
803e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            return;
804e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
805e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        mSession.dispatchSurfaceChanged(format, width, height);
806e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    }
807e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
8089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void createSessionOverlayView() {
8099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null || !isAttachedToWindow()
810bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho                || mOverlayViewCreated || mWindowZOrder != ZORDER_MEDIA) {
8119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = getViewFrameOnScreen();
8149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.createOverlayView(this, mOverlayViewFrame);
8159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewCreated = true;
8169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void removeSessionOverlayView() {
8199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null || !mOverlayViewCreated) {
8209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.removeOverlayView();
8239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewCreated = false;
8249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = null;
8259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void relayoutSessionOverlayView() {
828bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSession == null || !isAttachedToWindow() || !mOverlayViewCreated
829bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho                || mWindowZOrder != ZORDER_MEDIA) {
8309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        Rect viewFrame = getViewFrameOnScreen();
8339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (viewFrame.equals(mOverlayViewFrame)) {
8349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.relayoutOverlayView(viewFrame);
8379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = viewFrame;
8389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Rect getViewFrameOnScreen() {
8419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        int[] location = new int[2];
8429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        getLocationOnScreen(location);
8439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        return new Rect(location[0], location[1],
8449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                location[0] + getWidth(), location[1] + getHeight());
8459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
848465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Callback used to receive time shift position changes.
8496f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
8506f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public abstract static class TimeShiftPositionCallback {
851465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo
8526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
8534e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the start position for time shifting has changed.
8540610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         *
8554e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>The start position for time shifting indicates the earliest possible time the user can
8564e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * seek to. Initially this is equivalent to the time when the underlying TV input starts
8574e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * recording. Later it may be adjusted because there is insufficient space or the duration
8584e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * of recording is limited. The application must not allow the user to seek to a position
8594e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * earlier than the start position.
8606f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
8614e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>For playback of a recorded program initiated by {@link #timeShiftPlay(String, Uri)},
8624e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * the start position is the time when playback starts. It does not change.
8633d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo         *
8646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
8654e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
8666f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
8676f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
8686f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
8696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
8706f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
8714e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the current position for time shifting has changed.
8726f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
8734e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>The current position for time shifting is the same as the current position of
8744e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * playback. During playback, the current position changes continuously. When paused, it
8754e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * does not change.
8764e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         *
8774e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>Note that {@code timeMs} is wall-clock time.
8783d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo         *
8796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
8804e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
8816f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
8826f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
8836f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
8846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
8856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
8866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
8872778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Callback used to receive various status updates on the {@link TvView}.
888b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
8892778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public abstract static class TvInputCallback {
890b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
891b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
8921553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * This is invoked when an error occurred while establishing a connection to the underlying
8931553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * TV input.
8941553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         *
8951553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * @param inputId The ID of the TV input bound to this view.
8961553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         */
8971553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        public void onConnectionFailed(String inputId) {
8981553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        }
8991553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo
9001553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        /**
9011553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * This is invoked when the existing connection to the underlying TV input is lost.
902b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
903b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param inputId The ID of the TV input bound to this view.
904b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
9051553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        public void onDisconnected(String inputId) {
906b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
907b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
908b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
9091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is invoked when the channel of this TvView is changed by the underlying TV input
910e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang         * without any {@link TvView#tune} request.
911b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
912b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param inputId The ID of the TV input bound to this view.
9131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param channelUri The URI of a channel.
914b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
9151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(String inputId, Uri channelUri) {
916b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
917b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
918b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
9191f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the track information has been changed.
920b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         *
921b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         * @param inputId The ID of the TV input bound to this view.
9221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param tracks A list which includes track information.
923b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         */
92410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(String inputId, List<TvTrackInfo> tracks) {
925b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
926b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
927b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        /**
928d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * This is called when there is a change on the selected tracks.
929d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         *
930d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param inputId The ID of the TV input bound to this view.
93110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the track selected. The type can be
93210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
93310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
93410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the track selected.
935d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
93610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(String inputId, int type, String trackId) {
937d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
938d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
939d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
9406320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * This is invoked when the video size has been changed. It is also called when the first
9416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * time video size information becomes available after this view is tuned to a specific
9426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * channel.
9436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         *
9446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param inputId The ID of the TV input bound to this view.
9456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param width The width of the video.
9466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param height The height of the video.
9476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
9486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(String inputId, int width, int height) {
9496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
9506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
9516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
9529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is available, so the TV input starts the playback.
9539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
9549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param inputId The ID of the TV input bound to this view.
9559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
9569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoAvailable(String inputId) {
9579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
9589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
9609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is not available, so the TV input stops the playback.
9619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
9629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param inputId The ID of the TV input bound to this view.
9639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param reason The reason why the TV input stopped the playback:
9649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <ul>
9659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
9666e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
9679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
9689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
969ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
9709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * </ul>
9719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
9723b9be6700fd631e25559693820d03389f8de3893Jae Seo        public void onVideoUnavailable(
9733b9be6700fd631e25559693820d03389f8de3893Jae Seo                String inputId, @TvInputManager.VideoUnavailableReason int reason) {
9749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
9759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
977bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be allowed to watch since
978bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * its content rating is not blocked by parental controls.
979bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         *
980bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * @param inputId The ID of the TV input bound to this view.
981bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         */
982bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(String inputId) {
983bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
984bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
985bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        /**
986bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be not allowed to watch
987bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * since its content rating is blocked by parental controls.
9886057102dbb746593a7d59cf377c969b62e38c664Jae Seo         *
9896057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param inputId The ID of the TV input bound to this view.
9906057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param rating The content rating of the blocked program.
9916057102dbb746593a7d59cf377c969b62e38c664Jae Seo         */
9926057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(String inputId, TvContentRating rating) {
9936057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
9946057102dbb746593a7d59cf377c969b62e38c664Jae Seo
9956057102dbb746593a7d59cf377c969b62e38c664Jae Seo        /**
996b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * This is invoked when a custom event from the bound TV input is sent to this view.
997b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
9986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
999b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param eventType The type of the event.
1000b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param eventArgs Optional arguments of the event.
1001b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @hide
1002b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
100315bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
1004b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        public void onEvent(String inputId, String eventType, Bundle eventArgs) {
1005b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
10066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
10076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
10086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * This is called when the time shift status is changed.
10096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
10106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
1011465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @param status The current time shift status. Should be one of the followings.
10126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <ul>
1013465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
10146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
1015465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
10166f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * </ul>
10176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
10183b9be6700fd631e25559693820d03389f8de3893Jae Seo        public void onTimeShiftStatusChanged(
10193b9be6700fd631e25559693820d03389f8de3893Jae Seo                String inputId, @TvInputManager.TimeShiftStatus int status) {
10206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
1021b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
1022b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
1023b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
10246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * Interface definition for a callback to be invoked when the unhandled input event is received.
10256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
10266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public interface OnUnhandledInputEventListener {
10276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
10286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Called when an input event was not handled by the bound TV input.
10290610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         *
10300610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         * <p>This is called asynchronously from where the event is dispatched. It gives the host
10316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * application a chance to handle the unhandled input events.
10326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
10336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param event The input event.
10346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @return If you handled the event, return {@code true}. If you want to allow the event to
10356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         be handled by the next receiver, return {@code false}.
10366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
10376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        boolean onUnhandledInputEvent(InputEvent event);
10386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
10396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
10402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private class MySessionCallback extends SessionCallback {
1041b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        final String mInputId;
1042b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        Uri mChannelUri;
10431a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        Bundle mTuneParams;
1044a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        Uri mRecordedProgramUri;
10459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
10461a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        MySessionCallback(String inputId, Uri channelUri, Bundle tuneParams) {
1047b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            mInputId = inputId;
1048b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            mChannelUri = channelUri;
10491a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            mTuneParams = tuneParams;
10509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
10519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1052a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        MySessionCallback(String inputId, Uri recordedProgramUri) {
1053a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mInputId = inputId;
1054a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mRecordedProgramUri = recordedProgramUri;
1055a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
1056a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
10579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
10589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void onSessionCreated(Session session) {
10596320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
10606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onSessionCreated()");
10616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
10622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (this != mSessionCallback) {
10636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionCreated - session already created");
10649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // This callback is obsolete.
1065c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                if (session != null) {
1066c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                    session.release();
1067c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                }
10689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                return;
10699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
10709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSession = session;
10719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (session != null) {
1072411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                // Sends the pending app private commands first.
1073411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                for (Pair<String, Bundle> command : mPendingAppPrivateCommands) {
1074411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                    mSession.sendAppPrivateCommand(command.first, command.second);
1075411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                }
1076411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                mPendingAppPrivateCommands.clear();
1077411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo
10784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (sMainTvViewLock) {
1079c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee                    if (hasWindowFocus() && TvView.this == sMainTvView.get()) {
108015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        mSession.setMain();
10814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
10824c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
10839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // mSurface may not be ready yet as soon as starting an application.
10849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // In the case, we don't send Session.setSurface(null) unnecessarily.
10859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // setSessionSurface will be called in surfaceCreated.
10869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                if (mSurface != null) {
10879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    setSessionSurface(mSurface);
1088e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    if (mSurfaceChanged) {
1089e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
1090e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
10919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
10929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                createSessionOverlayView();
10931da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                if (mStreamVolume != null) {
1094336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang                    mSession.setStreamVolume(mStreamVolume);
1095336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang                }
10961da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                if (mCaptionEnabled != null) {
10971da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                    mSession.setCaptionEnabled(mCaptionEnabled);
10981da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                }
1099a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                if (mChannelUri != null) {
1100a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSession.tune(mChannelUri, mTuneParams);
1101a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                } else {
1102a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSession.timeShiftPlay(mRecordedProgramUri);
1103a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1104465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                ensurePositionTracking();
1105b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            } else {
11067cf67054550e8e6ea2379d7b0f0653796ce85062Youngsang Cho                mSessionCallback = null;
11072778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                if (mCallback != null) {
11082778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onConnectionFailed(mInputId);
1109b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo                }
11109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
11119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
11122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
11132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
11142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionReleased(Session session) {
11156320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11166320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onSessionReleased()");
11176320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1118e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
11196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionReleased - session not created");
1120e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
11211f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
1122ffad70bb7efe08ab8f03cb93e783714232a101acChulwoo Lee            mOverlayViewCreated = false;
1123ffad70bb7efe08ab8f03cb93e783714232a101acChulwoo Lee            mOverlayViewFrame = null;
1124e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSessionCallback = null;
11252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSession = null;
11262778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11272778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onDisconnected(mInputId);
11282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
11292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
1130832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
1131832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        @Override
11321f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(Session session, Uri channelUri) {
1133a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            if (DEBUG) {
11341f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Log.d(TAG, "onChannelChangedByTvInput(" + channelUri + ")");
1135a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
11366320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
11376320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onChannelRetuned - session not created");
11386320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
11396320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11402778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11412778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onChannelRetuned(mInputId, channelUri);
1142a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
1143a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang        }
1144a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
1145a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang        @Override
114610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(Session session, List<TvTrackInfo> tracks) {
11476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onTracksChanged(" + tracks + ")");
11496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11501f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            if (this != mSessionCallback) {
11516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onTracksChanged - session not created");
11521f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                return;
1153832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
11542778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11552778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onTracksChanged(mInputId, tracks);
1156b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
1157b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
1158b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
11596057102dbb746593a7d59cf377c969b62e38c664Jae Seo        @Override
116010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(Session session, int type, String trackId) {
11616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
11636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1164d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            if (this != mSessionCallback) {
11656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onTrackSelected - session not created");
1166d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                return;
1167d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
11682778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11692778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onTrackSelected(mInputId, type, trackId);
1170d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
1171d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
1172d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
1173d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        @Override
11746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(Session session, int width, int height) {
11756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onVideoSizeChanged()");
11776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1178e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
11796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoSizeChanged - session not created");
1180e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1181e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
11826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (mCallback != null) {
11836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mCallback.onVideoSizeChanged(mInputId, width, height);
11846320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
11866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
11876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        @Override
11886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoAvailable(Session session) {
11899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            if (DEBUG) {
11909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                Log.d(TAG, "onVideoAvailable()");
11919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
11926320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
11936320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoAvailable - session not created");
11946320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
11956320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11962778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11972778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onVideoAvailable(mInputId);
11989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
11999b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
12009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
12016057102dbb746593a7d59cf377c969b62e38c664Jae Seo        @Override
12029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoUnavailable(Session session, int reason) {
12036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
12046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onVideoUnavailable(reason=" + reason + ")");
12056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1206e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
12076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoUnavailable - session not created");
1208e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1209e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
12102778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12112778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onVideoUnavailable(mInputId, reason);
12129b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
12139b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
12149b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
1215b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        @Override
1216bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(Session session) {
1217bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            if (DEBUG) {
1218bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                Log.d(TAG, "onContentAllowed()");
1219bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
12206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onContentAllowed - session not created");
12226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
12242778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12252778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onContentAllowed(mInputId);
1226bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
1227bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
1228bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
1229bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        @Override
12306057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(Session session, TvContentRating rating) {
12316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
12326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onContentBlocked(rating=" + rating + ")");
12336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1234774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee            if (this != mSessionCallback) {
12356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onContentBlocked - session not created");
1236774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee                return;
1237774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee            }
12382778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12392778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onContentBlocked(mInputId, rating);
12406057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
12416057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
12426057102dbb746593a7d59cf377c969b62e38c664Jae Seo
1243bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        @Override
1244ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
1245ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            if (DEBUG) {
1246ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                Log.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top + ", right="
1247ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        + right + ", bottom=" + bottom + ",)");
1248ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
12496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onLayoutSurface - session not created");
12516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1253ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewLeft = left;
1254ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewTop = top;
1255ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewRight = right;
1256ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewBottom = bottom;
1257ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mUseRequestedSurfaceLayout = true;
1258ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            requestLayout();
1259ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
1260ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
1261ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        @Override
1262903d6b72cd572665309633e925485464d08bb25aJaewan Kim        public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
1263903d6b72cd572665309633e925485464d08bb25aJaewan Kim            if (DEBUG) {
1264903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Log.d(TAG, "onSessionEvent(" + eventType + ")");
1265903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
12666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionEvent - session not created");
12686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
12702778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12712778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onEvent(mInputId, eventType, eventArgs);
1272832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
1273832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
12746f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
12756f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
12766f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStatusChanged(Session session, int status) {
12776f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
12786f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftStatusChanged()");
12796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12806f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
12816f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftStatusChanged - session not created");
12826f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
12836f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mCallback != null) {
12856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                mCallback.onTimeShiftStatusChanged(mInputId, status);
12866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
12886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
12896f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
12906f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
12916f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
12926f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftStartPositionChanged()");
12936f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
12956f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftStartPositionChanged - session not created");
12966f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
12976f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
1298465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo            if (mTimeShiftPositionCallback != null) {
1299465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                mTimeShiftPositionCallback.onTimeShiftStartPositionChanged(mInputId, timeMs);
13006f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
13026f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
13036f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
13046f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
13056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
13066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftCurrentPositionChanged()");
13076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
13096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftCurrentPositionChanged - session not created");
13106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
13116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
1312465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo            if (mTimeShiftPositionCallback != null) {
1313465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                mTimeShiftPositionCallback.onTimeShiftCurrentPositionChanged(mInputId, timeMs);
13146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
13169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
13179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho}
1318