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;
283496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chenimport android.graphics.RectF;
295f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kangimport android.graphics.Region;
303d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seoimport android.media.PlaybackParams;
31d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.Session;
32d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
33d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputManager.SessionCallback;
34b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seoimport android.net.Uri;
35832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.os.Handler;
37d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Limimport android.text.TextUtils;
389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.AttributeSet;
399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Log;
40411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport android.util.Pair;
416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEvent;
426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.KeyEvent;
436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.MotionEvent;
449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.Surface;
459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.SurfaceHolder;
469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.SurfaceView;
4707b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Choimport android.view.View;
481bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seoimport android.view.ViewGroup;
49c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Leeimport android.view.ViewRootImpl;
509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
51c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Leeimport java.lang.ref.WeakReference;
52411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport java.util.ArrayDeque;
531f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport java.util.List;
54411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seoimport java.util.Queue;
551f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho/**
579551e92507564c597a7764473945114d3c3bfff3Jae Seo * Displays TV contents. The TvView class provides a high level interface for applications to show
589551e92507564c597a7764473945114d3c3bfff3Jae Seo * TV programs from various TV sources that implement {@link TvInputService}. (Note that the list of
599551e92507564c597a7764473945114d3c3bfff3Jae Seo * TV inputs available on the system can be obtained by calling
609551e92507564c597a7764473945114d3c3bfff3Jae Seo * {@link TvInputManager#getTvInputList() TvInputManager.getTvInputList()}.)
610610e12733875a267f59d87a2a68aebbf486066eDongwon Kang *
62e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * <p>Once the application supplies the URI for a specific TV channel to {@link #tune}
639551e92507564c597a7764473945114d3c3bfff3Jae Seo * method, it takes care of underlying service binding (and unbinding if the current TvView is
649551e92507564c597a7764473945114d3c3bfff3Jae Seo * already bound to a service) and automatically allocates/deallocates resources needed. In addition
659551e92507564c597a7764473945114d3c3bfff3Jae Seo * to a few essential methods to control how the contents are presented, it also provides a way to
669551e92507564c597a7764473945114d3c3bfff3Jae Seo * dispatch input events to the connected TvInputService in order to enable custom key actions for
679551e92507564c597a7764473945114d3c3bfff3Jae Seo * the TV input.
689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */
691bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seopublic class TvView extends ViewGroup {
70b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    private static final String TAG = "TvView";
71ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo    private static final boolean DEBUG = false;
72b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
73bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_MEDIA = 0;
74bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_MEDIA_OVERLAY = 1;
75bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private static final int ZORDER_ON_TOP = 2;
76bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    private static final WeakReference<TvView> NULL_TV_VIEW = new WeakReference<>(null);
78c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee
794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private static final Object sMainTvViewLock = new Object();
80c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee    private static WeakReference<TvView> sMainTvView = NULL_TV_VIEW;
814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private final Handler mHandler = new Handler();
83903d6b72cd572665309633e925485464d08bb25aJaewan Kim    private Session mSession;
8471b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private SurfaceView mSurfaceView;
859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Surface mSurface;
869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private boolean mOverlayViewCreated;
879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Rect mOverlayViewFrame;
886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final TvInputManager mTvInputManager;
89b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    private MySessionCallback mSessionCallback;
902778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private TvInputCallback mCallback;
916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
921da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo    private Float mStreamVolume;
931da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo    private Boolean mCaptionEnabled;
94411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo    private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
95887f52144eeea8d5812d64a29e207af6b97a763dJae Seo
96e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private boolean mSurfaceChanged;
97e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceFormat;
98e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceWidth;
99e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private int mSurfaceHeight;
10071b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private final AttributeSet mAttrs;
10171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private final int mDefStyleAttr;
102bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    private int mWindowZOrder;
103ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private boolean mUseRequestedSurfaceLayout;
104ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewLeft;
105ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewRight;
106ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewTop;
107ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho    private int mSurfaceViewBottom;
108465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    private TimeShiftPositionCallback mTimeShiftPositionCallback;
1099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
1119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
11315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
11415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width="
11515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    + width + ", height=" + height + ")");
11615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
117e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceFormat = format;
118e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceWidth = width;
119e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceHeight = height;
120e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceChanged = true;
121e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
1229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceCreated(SurfaceHolder holder) {
1269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSurface = holder.getSurface();
1279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            setSessionSurface(mSurface);
1289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
1319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void surfaceDestroyed(SurfaceHolder holder) {
1329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSurface = null;
133e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSurfaceChanged = false;
1349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            setSessionSurface(null);
1359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    };
1379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    private final FinishedInputEventCallback mFinishedInputEventCallback =
1396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            new FinishedInputEventCallback() {
1406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        @Override
1416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public void onFinishedInputEvent(Object token, boolean handled) {
1426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (DEBUG) {
1436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Log.d(TAG, "onFinishedInputEvent(token=" + token + ", handled=" + handled + ")");
1446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
1456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (handled) {
1466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return;
1476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
1486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            // TODO: Re-order unhandled events.
1496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            InputEvent event = (InputEvent) token;
1506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (dispatchUnhandledInputEvent(event)) {
1516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return;
1526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
153c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            ViewRootImpl viewRootImpl = getViewRootImpl();
154c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            if (viewRootImpl != null) {
155c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee                viewRootImpl.dispatchUnhandledInputEvent(event);
156c3e00c3ffc3b1406712f1f19b8d1cd815eee88daChulwoo Lee            }
1576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
1586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    };
1596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
1609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context) {
1619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        this(context, null, 0);
1629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context, AttributeSet attrs) {
1659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        this(context, attrs, 0);
1669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    public TvView(Context context, AttributeSet attrs, int defStyleAttr) {
1699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super(context, attrs, defStyleAttr);
17071b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mAttrs = attrs;
17171b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mDefStyleAttr = defStyleAttr;
17271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        resetSurfaceView();
1739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
1749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    /**
1772778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Sets the callback to be invoked when an event is dispatched to this TvView.
1789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho     *
179465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param callback The callback to receive events. A value of {@code null} removes the existing
180465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     *            callback.
1819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho     */
1824bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang    public void setCallback(@Nullable TvInputCallback callback) {
1832778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        mCallback = callback;
1849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
1859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
18715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * Sets this as the main {@link TvView}.
1880610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
1890610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>The main {@link TvView} is a {@link TvView} whose corresponding TV input determines the
19015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * HDMI-CEC active source device. For an HDMI port input, one of source devices that is
19115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * connected to that HDMI port becomes the active source. For an HDMI-CEC logical device input,
19215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * the corresponding HDMI-CEC logical device becomes the active source. For any non-HDMI input
19315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * (including the tuner, composite, S-Video, etc.), the internal device (= TV itself) becomes
19415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee     * the active source.
1950610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
1960610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>First tuned {@link TvView} becomes main automatically, and keeps to be main until either
1976e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo     * {@link #reset} is called for the main {@link TvView} or {@code setMain()} is called for other
198c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee     * {@link TvView}.
1994c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee     * @hide
2004c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee     */
2014c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    @SystemApi
20215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    public void setMain() {
2034c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
2046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            sMainTvView = new WeakReference<>(this);
2054c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            if (hasWindowFocus() && mSession != null) {
20615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                mSession.setMain();
2074c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
2084c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
2094c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
2104c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
2114c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    /**
212e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Controls whether the TvView's surface is placed on top of another regular surface view in the
213e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * window (but still behind the window itself).
214e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * This is typically used to place overlays on top of an underlying TvView.
215bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     *
216e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Note that this must be set before the TvView's containing window is attached to the
217e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * window manager.
218e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
219e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
220e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
221e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false}
222e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            otherwise.
223bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     */
224bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    public void setZOrderMediaOverlay(boolean isMediaOverlay) {
225bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (isMediaOverlay) {
226bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA_OVERLAY;
227bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            removeSessionOverlayView();
228bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else {
229bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA;
230bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            createSessionOverlayView();
231bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
232bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSurfaceView != null) {
233bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            // ZOrderOnTop(false) removes WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
234bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            // from WindowLayoutParam as well as changes window type.
235bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(false);
236bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(isMediaOverlay);
237bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
238bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    }
239bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
240bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    /**
241e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Controls whether the TvView's surface is placed on top of its window. Normally it is placed
242e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * behind the window, to allow it to (for the most part) appear to composite with the views in
243e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * the hierarchy.  By setting this, you cause it to be placed above the window. This means that
244e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * none of the contents of the window this TvView is in will be visible on top of its surface.
245bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     *
246e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Note that this must be set before the TvView's containing window is attached to the window
247e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * manager.
248e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
249e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}.
250e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *
251e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param onTop {@code true} to be on top of its window, {@code false} otherwise.
252bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     */
253bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    public void setZOrderOnTop(boolean onTop) {
254bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (onTop) {
255bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_ON_TOP;
256bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            removeSessionOverlayView();
257bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else {
258bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mWindowZOrder = ZORDER_MEDIA;
259bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            createSessionOverlayView();
260bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
261bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSurfaceView != null) {
262bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(false);
263bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(onTop);
264bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
265bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho     }
266bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho
267bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho    /**
2681da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * Sets the relative stream volume of this TvView.
2691da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     *
2701da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * <p>This method is primarily used to handle audio focus changes or mute a specific TvView when
2711da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * multiple views are displayed. If the method has not yet been called, the TvView assumes the
2721da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * default value of {@code 1.0f}.
273782f7345471072b630e58c7abd3579b0015273b1Jae Seo     *
2741da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo     * @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
275782f7345471072b630e58c7abd3579b0015273b1Jae Seo     */
276cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public void setStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {
277782f7345471072b630e58c7abd3579b0015273b1Jae Seo        if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
278336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang        mStreamVolume = volume;
279782f7345471072b630e58c7abd3579b0015273b1Jae Seo        if (mSession == null) {
280336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang            // Volume will be set once the connection has been made.
281782f7345471072b630e58c7abd3579b0015273b1Jae Seo            return;
282782f7345471072b630e58c7abd3579b0015273b1Jae Seo        }
283782f7345471072b630e58c7abd3579b0015273b1Jae Seo        mSession.setStreamVolume(volume);
284782f7345471072b630e58c7abd3579b0015273b1Jae Seo    }
285782f7345471072b630e58c7abd3579b0015273b1Jae Seo
286782f7345471072b630e58c7abd3579b0015273b1Jae Seo    /**
287b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * Tunes to a given channel.
288b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     *
289b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo     * @param inputId The ID of the TV input for the given channel.
290b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @param channelUri The URI of a channel.
291b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
292c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void tune(@NonNull String inputId, Uri channelUri) {
2931a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        tune(inputId, channelUri, null);
2941a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    }
2951a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
2961a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    /**
297e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * Tunes to a given channel. This can be used to provide domain-specific features that are only
298f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * known between certain clients and their TV inputs.
2991a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     *
300b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo     * @param inputId The ID of TV input for the given channel.
3011a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     * @param channelUri The URI of a channel.
302e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
303e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            name, i.e. prefixed with a package name you own, so that different developers will
304e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     *            not create conflicting keys.
3051a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim     */
3061a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim    public void tune(String inputId, Uri channelUri, Bundle params) {
307b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (DEBUG) Log.d(TAG, "tune(" + channelUri + ")");
308b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (TextUtils.isEmpty(inputId)) {
309b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            throw new IllegalArgumentException("inputId cannot be null or an empty string");
310b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
3114c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
312c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (sMainTvView.get() == null) {
3136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                sMainTvView = new WeakReference<>(this);
3144c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
3154c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
316b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
317b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            if (mSession != null) {
3181a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mSession.tune(channelUri, params);
319b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            } else {
320b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // createSession() was called but the actual session for the given inputId has not
321b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // yet been created. Just replace the existing tuning params in the callback with
322b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // the new ones and tune later in onSessionCreated(). It is not necessary to create
323b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo                // a new callback because this tuning request was made on the same inputId.
324b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo                mSessionCallback.mChannelUri = channelUri;
3251a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mSessionCallback.mTuneParams = params;
326b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            }
327b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        } else {
328d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee            resetInternal();
329b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // In case createSession() is called multiple times across different inputId's before
330b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // any session is created (e.g. when quickly tuning to a channel from input A and then
331b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // to another channel from input B), only the callback for the last createSession()
332b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // should be invoked. (The previous callbacks are simply ignored.) To do that, we create
333b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // a new callback each time and keep mSessionCallback pointing to the last one. If
334b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // MySessionCallback.this is different from mSessionCallback, we know that this callback
335b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo            // is obsolete and should ignore it.
3361a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            mSessionCallback = new MySessionCallback(inputId, channelUri, params);
3379127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            if (mTvInputManager != null) {
3389127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
3399127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            }
340b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
341b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
342b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
343b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
344b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * Resets this TvView.
3450610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
3460610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>This method is primarily used to un-tune the current TvView.
347b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
348b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    public void reset() {
34915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (DEBUG) Log.d(TAG, "reset()");
350c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee        synchronized (sMainTvViewLock) {
351c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (this == sMainTvView.get()) {
352c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee                sMainTvView = NULL_TV_VIEW;
353c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            }
354c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee        }
355d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee        resetInternal();
356d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee    }
357d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee
358d0f00588834806d3f52c95c2d5fb13d9a92bddfcJi-Hwan Lee    private void resetInternal() {
359b1ae00ec628d16c2fd1354c70e971d4757201753Jae Seo        mSessionCallback = null;
36017345072864b9aeb4e5535257e83e6809859ae0fJae Seo        mPendingAppPrivateCommands.clear();
361b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        if (mSession != null) {
36217345072864b9aeb4e5535257e83e6809859ae0fJae Seo            setSessionSurface(null);
36317345072864b9aeb4e5535257e83e6809859ae0fJae Seo            removeSessionOverlayView();
36417345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mUseRequestedSurfaceLayout = false;
36517345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mSession.release();
36617345072864b9aeb4e5535257e83e6809859ae0fJae Seo            mSession = null;
36771b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            resetSurfaceView();
368b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
369b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
370b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
371b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
3729bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim     * Requests to unblock TV content according to the given rating.
3730610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
3740610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>This notifies TV input that blocked content is now OK to play.
375903d6b72cd572665309633e925485464d08bb25aJaewan Kim     *
3769bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim     * @param unblockedRating A TvContentRating to unblock.
37791a801d42f3acc35404da51ba26605093922503aJae Seo     * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
378e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang     * @removed
379903d6b72cd572665309633e925485464d08bb25aJaewan Kim     */
3809bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim    public void requestUnblockContent(TvContentRating unblockedRating) {
381a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo        unblockContent(unblockedRating);
382a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    }
383a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo
384a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    /**
385a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * Requests to unblock TV content according to the given rating.
386a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     *
387a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * <p>This notifies TV input that blocked content is now OK to play.
388a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     *
389a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @param unblockedRating A TvContentRating to unblock.
390a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @see TvInputService.Session#notifyContentBlocked(TvContentRating)
391a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     * @hide
392a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo     */
393a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    @SystemApi
394e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
395a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo    public void unblockContent(TvContentRating unblockedRating) {
396903d6b72cd572665309633e925485464d08bb25aJaewan Kim        if (mSession != null) {
397a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo            mSession.unblockContent(unblockedRating);
398903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
399903d6b72cd572665309633e925485464d08bb25aJaewan Kim    }
400903d6b72cd572665309633e925485464d08bb25aJaewan Kim
401903d6b72cd572665309633e925485464d08bb25aJaewan Kim    /**
4022c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     * Enables or disables the caption in this TvView.
4030610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
4040610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Note that this method does not take any effect unless the current TvView is tuned.
4052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     *
4062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     * @param enabled {@code true} to enable, {@code false} to disable.
4072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     */
4082c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    public void setCaptionEnabled(boolean enabled) {
4091da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo        if (DEBUG) Log.d(TAG, "setCaptionEnabled(" + enabled + ")");
4101da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo        mCaptionEnabled = enabled;
4112c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        if (mSession != null) {
4122c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            mSession.setCaptionEnabled(enabled);
4132c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
4142c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    }
4152c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
4162c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo    /**
4171f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Selects a track.
4182c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo     *
41910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the track to select. The type can be {@link TvTrackInfo#TYPE_AUDIO},
42010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
42110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param trackId The ID of the track to select. {@code null} means to unselect the current
42210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            track for a given type.
42310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getTracks
42410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getSelectedTrack
4251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     */
42610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public void selectTrack(int type, String trackId) {
4271f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        if (mSession != null) {
42810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            mSession.selectTrack(type, trackId);
4291f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
4301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    }
4311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
4321f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    /**
43310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * Returns the list of tracks. Returns {@code null} if the information is not available.
4341f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     *
43510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
43610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
43710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #selectTrack
43810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getSelectedTrack
4391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang     */
44010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public List<TvTrackInfo> getTracks(int type) {
4411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        if (mSession == null) {
4421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            return null;
4431f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
44410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        return mSession.getTracks(type);
4451f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    }
4461f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
4471f213914c45c23c653f721690da2ce0718e63139Dongwon Kang    /**
44810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * Returns the ID of the selected track for a given type. Returns {@code null} if the
44910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * information is not available or the track is not selected.
45010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *
45110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @param type The type of the selected tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
45210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
45310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #selectTrack
45410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo     * @see #getTracks
455d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo     */
45610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo    public String getSelectedTrack(int type) {
457d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        if (mSession == null) {
458d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            return null;
459d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
46010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        return mSession.getSelectedTrack(type);
461d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo    }
462d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
463d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo    /**
464a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * Plays a given recorded TV program.
465a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     *
466a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input that created the given recorded program.
467a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param recordedProgramUri The URI of a recorded program.
468a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     */
469a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    public void timeShiftPlay(String inputId, Uri recordedProgramUri) {
470a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (DEBUG) Log.d(TAG, "timeShiftPlay(" + recordedProgramUri + ")");
471a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (TextUtils.isEmpty(inputId)) {
472a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            throw new IllegalArgumentException("inputId cannot be null or an empty string");
473a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
474a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        synchronized (sMainTvViewLock) {
475a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (sMainTvView.get() == null) {
476a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                sMainTvView = new WeakReference<>(this);
477a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
478a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
479a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
480a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mSession != null) {
481a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mSession.timeShiftPlay(recordedProgramUri);
482a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            } else {
483a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mSessionCallback.mRecordedProgramUri = recordedProgramUri;
484a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
485a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        } else {
486a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            resetInternal();
487a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mSessionCallback = new MySessionCallback(inputId, recordedProgramUri);
488a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mTvInputManager != null) {
489a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
490a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
491a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
492a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    }
493a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
494a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /**
495465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Pauses playback. No-op if it is already paused. Call {@link #timeShiftResume} to resume.
4966f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
4976f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftPause() {
4986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
4996f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftPause();
5006f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5026f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5036f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
504465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Resumes playback. No-op if it is already resumed. Call {@link #timeShiftPause} to pause.
5056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftResume() {
5076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftResume();
5096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
513465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Seeks to a specified time position. {@code timeMs} must be equal to or greater than the start
514465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * position returned by {@link TimeShiftPositionCallback#onTimeShiftStartPositionChanged} and
515465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * equal to or less than the current time.
5166f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
517465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param timeMs The time position to seek to, in milliseconds since the epoch.
5186f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5196f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public void timeShiftSeekTo(long timeMs) {
5206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5216f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mSession.timeShiftSeekTo(timeMs);
5226f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5236f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5246f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5256f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
5264b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo     * Sets playback rate using {@link android.media.PlaybackParams}.
5276f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
5283d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo     * @param params The playback params.
5296f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5303d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo    public void timeShiftSetPlaybackParams(@NonNull PlaybackParams params) {
5316f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession != null) {
5324b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo            mSession.timeShiftSetPlaybackParams(params);
5336f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5346f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5366f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
537465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Sets the callback to be invoked when the time shift position is changed.
5386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     *
539465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * @param callback The callback to receive time shift position changes. A value of {@code null}
540465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     *            removes the existing callback.
5416f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
5424bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang    public void setTimeShiftPositionCallback(@Nullable TimeShiftPositionCallback callback) {
543465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        mTimeShiftPositionCallback = callback;
544465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        ensurePositionTracking();
5456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
547465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    private void ensurePositionTracking() {
5486f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        if (mSession == null) {
5496f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            return;
5506f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
551465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        mSession.timeShiftEnablePositionTracking(mTimeShiftPositionCallback != null);
5526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
5536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5546f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
555f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * Sends a private command to the underlying TV input. This can be used to provide
556f714e62c12d99d816d70d09da60b6885a1368cefDongwon Kang     * domain-specific features that are only known between certain clients and their TV inputs.
557a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo     *
558887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     * @param action The name of the private command to send. This <em>must</em> be a scoped name,
559887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     *            i.e. prefixed with a package name you own, so that different developers will not
560887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     *            create conflicting commands.
561887f52144eeea8d5812d64a29e207af6b97a763dJae Seo     * @param data An optional bundle to send with the command.
562a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo     */
563c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void sendAppPrivateCommand(@NonNull String action, Bundle data) {
564a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        if (TextUtils.isEmpty(action)) {
565a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            throw new IllegalArgumentException("action cannot be null or an empty string");
566a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
567a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        if (mSession != null) {
568a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            mSession.sendAppPrivateCommand(action, data);
569887f52144eeea8d5812d64a29e207af6b97a763dJae Seo        } else {
570411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo            Log.w(TAG, "sendAppPrivateCommand - session not yet created (action \"" + action
571411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                    + "\" pending)");
572411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo            mPendingAppPrivateCommands.add(Pair.create(action, data));
573a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
574a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo    }
575a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
576a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo    /**
5776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * Dispatches an unhandled input event to the next receiver.
5780610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
5790610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Except system keys, TvView always consumes input events in the normal flow. This is called
5806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * asynchronously from where the event is dispatched. It gives the host application a chance to
5816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * dispatch the unhandled input events.
5826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
5836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @param event The input event.
5846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @return {@code true} if the event was handled by the view, {@code false} otherwise.
5856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
5866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchUnhandledInputEvent(InputEvent event) {
5876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mOnUnhandledInputEventListener != null) {
5886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (mOnUnhandledInputEventListener.onUnhandledInputEvent(event)) {
5896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return true;
5906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
5916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
5926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return onUnhandledInputEvent(event);
5936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
5946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
5956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
5961f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Called when an unhandled input event also has not been handled by the user provided
5971f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * callback. This is the last chance to handle the unhandled input event in the TvView.
5986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
5996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @param event The input event.
6006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * @return If you handled the event, return {@code true}. If you want to allow the event to be
6016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *         handled by the next receiver, return {@code false}.
6026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
6036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean onUnhandledInputEvent(InputEvent event) {
6046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return false;
6056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
6081f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * Registers a callback to be invoked when an input event is not handled by the bound TV input.
6096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     *
6101f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang     * @param listener The callback to be invoked when the unhandled input event is received.
6116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
6126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public void setOnUnhandledInputEventListener(OnUnhandledInputEventListener listener) {
6136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        mOnUnhandledInputEventListener = listener;
6146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchKeyEvent(KeyEvent event) {
6186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchKeyEvent(event)) {
6196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")");
6226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
625f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
626f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
627f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchTouchEvent(MotionEvent event) {
6336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchTouchEvent(event)) {
6346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchTouchEvent(" + event + ")");
6376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
640f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
641f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
642f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchTrackballEvent(MotionEvent event) {
6486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchTrackballEvent(event)) {
6496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchTrackballEvent(" + event + ")");
6526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
655f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
656f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
657f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    @Override
6626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public boolean dispatchGenericMotionEvent(MotionEvent event) {
6636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (super.dispatchGenericMotionEvent(event)) {
6646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return true;
6656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
6666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent(" + event + ")");
6676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        if (mSession == null) {
6686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return false;
6696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
670f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        InputEvent copiedEvent = event.copy();
671f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
672f982613c81ef89cf33cc99498649e624b2a94a58Youngsang Cho                mHandler);
6736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        return ret != Session.DISPATCH_NOT_HANDLED;
6746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
6756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
6769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
6774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    public void dispatchWindowFocusChanged(boolean hasFocus) {
6784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        super.dispatchWindowFocusChanged(hasFocus);
6794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // Other app may have shown its own main TvView.
6804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // Set main again to regain main session.
6814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        synchronized (sMainTvViewLock) {
682c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee            if (hasFocus && this == sMainTvView.get() && mSession != null) {
68315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                mSession.setMain();
6844c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
6854c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
6864c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
6874c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
6884c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    @Override
6899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    protected void onAttachedToWindow() {
6909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super.onAttachedToWindow();
6919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        createSessionOverlayView();
6929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
6939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
6949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
6959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    protected void onDetachedFromWindow() {
6969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        removeSessionOverlayView();
6979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        super.onDetachedFromWindow();
6989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
6999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
7009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    @Override
7011bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
702ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        if (DEBUG) {
703ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            Log.d(TAG, "onLayout (left=" + left + ", top=" + top + ", right=" + right
704ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    + ", bottom=" + bottom + ",)");
705ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
706ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        if (mUseRequestedSurfaceLayout) {
707ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceView.layout(mSurfaceViewLeft, mSurfaceViewTop, mSurfaceViewRight,
708ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    mSurfaceViewBottom);
709ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        } else {
710ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceView.layout(0, 0, right - left, bottom - top);
711ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
7121bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    }
7131bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo
7141bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    @Override
7151bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
7161bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec);
7171bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int width = mSurfaceView.getMeasuredWidth();
7181bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int height = mSurfaceView.getMeasuredHeight();
7191bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        int childState = mSurfaceView.getMeasuredState();
7201bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
7211bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo                resolveSizeAndState(height, heightMeasureSpec,
7221bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo                        childState << MEASURED_HEIGHT_STATE_SHIFT));
7231bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    }
7241bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo
7251bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo    @Override
7265f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    public boolean gatherTransparentRegion(Region region) {
7275f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7285f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            if (region != null) {
7295f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                int width = getWidth();
7305f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                int height = getHeight();
7315f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                if (width > 0 && height > 0) {
7325f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int location[] = new int[2];
7335f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    getLocationInWindow(location);
7345f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int left = location[0];
7355f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    int top = location[1];
7365f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                    region.op(left, top, left + width, top + height, Region.Op.UNION);
7375f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang                }
7385f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            }
7395f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7405f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        return super.gatherTransparentRegion(region);
7415f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7425f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7435f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7445f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    public void draw(Canvas canvas) {
7455f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7465f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            // Punch a hole so that the underlying overlay view and surface can be shown.
7475f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
7485f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7495f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        super.draw(canvas);
7505f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7515f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7525f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7535f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    protected void dispatchDraw(Canvas canvas) {
7545f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        if (mWindowZOrder != ZORDER_ON_TOP) {
7555f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            // Punch a hole so that the underlying overlay view and surface can be shown.
7565f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
7575f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        }
7585f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang        super.dispatchDraw(canvas);
7595f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    }
7605f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang
7615f3cb4a584545927b3dcecb7cb47eb7edb6d2d5dDongwon Kang    @Override
7626a1f2649a917ddec808e75f31efeb227133dd096Christofer Ã…kersten    protected void onVisibilityChanged(View changedView, int visibility) {
7636a1f2649a917ddec808e75f31efeb227133dd096Christofer Ã…kersten        super.onVisibilityChanged(changedView, visibility);
7641bfce9fb9bffe8bd620fd1683572ae620f91772fJae Seo        mSurfaceView.setVisibility(visibility);
76507b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        if (visibility == View.VISIBLE) {
76607b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho            createSessionOverlayView();
76707b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        } else {
76807b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho            removeSessionOverlayView();
76907b7c5fa4cb705eea5d89f98e84341db5465d663Youngsang Cho        }
7709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
7719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
77271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    private void resetSurfaceView() {
77371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        if (mSurfaceView != null) {
77471b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback);
77571b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            removeView(mSurfaceView);
77671b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        }
77715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        mSurface = null;
77871b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
77971b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            @Override
780d5c7dd6da810a6b89151b337bea79fd817e6b72aRobert Carr            protected void updateSurface() {
781d5c7dd6da810a6b89151b337bea79fd817e6b72aRobert Carr                super.updateSurface();
78271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho                relayoutSessionOverlayView();
78371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho            }};
78422168a7dfccab1865bc43b4c43a340b27deee9bbJae Seo        // The surface view's content should be treated as secure all the time.
78522168a7dfccab1865bc43b4c43a340b27deee9bbJae Seo        mSurfaceView.setSecure(true);
78671b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
787bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mWindowZOrder == ZORDER_MEDIA_OVERLAY) {
788bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderMediaOverlay(true);
789bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        } else if (mWindowZOrder == ZORDER_ON_TOP) {
790bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho            mSurfaceView.setZOrderOnTop(true);
791bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        }
79271b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho        addView(mSurfaceView);
79371b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho    }
79471b282fad429dfa5e98287aa34af6aecd155321bYoungsang Cho
7959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void setSessionSurface(Surface surface) {
7969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null) {
7979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
7989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
7999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.setSurface(surface);
8009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
802e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    private void dispatchSurfaceChanged(int format, int width, int height) {
803e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        if (mSession == null) {
804e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            return;
805e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
806e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        mSession.dispatchSurfaceChanged(format, width, height);
807e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho    }
808e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
8099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void createSessionOverlayView() {
8109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null || !isAttachedToWindow()
811bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho                || mOverlayViewCreated || mWindowZOrder != ZORDER_MEDIA) {
8129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = getViewFrameOnScreen();
8159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.createOverlayView(this, mOverlayViewFrame);
8169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewCreated = true;
8179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void removeSessionOverlayView() {
8209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (mSession == null || !mOverlayViewCreated) {
8219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.removeOverlayView();
8249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewCreated = false;
8259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = null;
8269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private void relayoutSessionOverlayView() {
829bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho        if (mSession == null || !isAttachedToWindow() || !mOverlayViewCreated
830bf0a4eb158ff5352dd2e7c456339cd36c28bcb43Youngsang Cho                || mWindowZOrder != ZORDER_MEDIA) {
8319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        Rect viewFrame = getViewFrameOnScreen();
8349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (viewFrame.equals(mOverlayViewFrame)) {
8359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            return;
8369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
8379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mSession.relayoutOverlayView(viewFrame);
8389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        mOverlayViewFrame = viewFrame;
8399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    private Rect getViewFrameOnScreen() {
8423496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        Rect frame = new Rect();
8433496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        getGlobalVisibleRect(frame);
8443496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        RectF frameF = new RectF(frame);
8453496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        getMatrix().mapRect(frameF);
8463496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        frameF.round(frame);
8473496c38e50cd2a674dcd63886557f2b41c66ac0dConrad Chen        return frame;
8489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
8499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
8506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    /**
851465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     * Callback used to receive time shift position changes.
8526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
8536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public abstract static class TimeShiftPositionCallback {
854465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo
8556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
8564e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the start position for time shifting has changed.
8570610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         *
8584e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>The start position for time shifting indicates the earliest possible time the user can
8594e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * seek to. Initially this is equivalent to the time when the underlying TV input starts
8604e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * recording. Later it may be adjusted because there is insufficient space or the duration
8614e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * of recording is limited. The application must not allow the user to seek to a position
8624e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * earlier than the start position.
8636f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
8644e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>For playback of a recorded program initiated by {@link #timeShiftPlay(String, Uri)},
8654e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * the start position is the time when playback starts. It does not change.
8663d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo         *
8676f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
8684e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
8696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
8706f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
8716f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
8726f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
8736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
8744e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the current position for time shifting has changed.
8756f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
8764e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>The current position for time shifting is the same as the current position of
8774e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * playback. During playback, the current position changes continuously. When paused, it
8784e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * does not change.
8794e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         *
8804e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * <p>Note that {@code timeMs} is wall-clock time.
8813d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo         *
8826f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
8834e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
8846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
8856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
8866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
8876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    }
8886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
8896f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
8902778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Callback used to receive various status updates on the {@link TvView}.
891b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
8922778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public abstract static class TvInputCallback {
893b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
894b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
8951553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * This is invoked when an error occurred while establishing a connection to the underlying
8961553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * TV input.
8971553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         *
8981553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * @param inputId The ID of the TV input bound to this view.
8991553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         */
9001553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        public void onConnectionFailed(String inputId) {
9011553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        }
9021553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo
9031553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        /**
9041553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo         * This is invoked when the existing connection to the underlying TV input is lost.
905b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
906b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param inputId The ID of the TV input bound to this view.
907b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
9081553a528a5e2a2eeb94318601943fad2d9484bb3Jae Seo        public void onDisconnected(String inputId) {
909b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
910b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
911b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
9121f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is invoked when the channel of this TvView is changed by the underlying TV input
913e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang         * without any {@link TvView#tune} request.
914b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
915b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param inputId The ID of the TV input bound to this view.
9161f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param channelUri The URI of a channel.
917b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
9181f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(String inputId, Uri channelUri) {
919b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
920b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
921b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        /**
9221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the track information has been changed.
923b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         *
924b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         * @param inputId The ID of the TV input bound to this view.
9251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param tracks A list which includes track information.
926b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         */
92710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(String inputId, List<TvTrackInfo> tracks) {
928b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
929b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
930b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        /**
931d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * This is called when there is a change on the selected tracks.
932d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         *
933d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param inputId The ID of the TV input bound to this view.
93410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the track selected. The type can be
93510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
93610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
93710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the track selected.
938d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
93910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(String inputId, int type, String trackId) {
940d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
941d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
942d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
9436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * This is invoked when the video size has been changed. It is also called when the first
9446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * time video size information becomes available after this view is tuned to a specific
9456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * channel.
9466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         *
9476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param inputId The ID of the TV input bound to this view.
9486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param width The width of the video.
9496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param height The height of the video.
9506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
9516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(String inputId, int width, int height) {
9526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
9536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
9546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
9559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is available, so the TV input starts the playback.
9569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
9579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param inputId The ID of the TV input bound to this view.
9589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
9599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoAvailable(String inputId) {
9609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
9619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
9639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is not available, so the TV input stops the playback.
9649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
9659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param inputId The ID of the TV input bound to this view.
9669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param reason The reason why the TV input stopped the playback:
9679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <ul>
9689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
9696e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
9709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
9719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
972ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
9739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * </ul>
9749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
9753b9be6700fd631e25559693820d03389f8de3893Jae Seo        public void onVideoUnavailable(
9763b9be6700fd631e25559693820d03389f8de3893Jae Seo                String inputId, @TvInputManager.VideoUnavailableReason int reason) {
9779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
9789b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
980bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be allowed to watch since
981bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * its content rating is not blocked by parental controls.
982bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         *
983bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * @param inputId The ID of the TV input bound to this view.
984bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         */
985bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(String inputId) {
986bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
987bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
988bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        /**
989bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be not allowed to watch
990bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * since its content rating is blocked by parental controls.
9916057102dbb746593a7d59cf377c969b62e38c664Jae Seo         *
9926057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param inputId The ID of the TV input bound to this view.
9936057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param rating The content rating of the blocked program.
9946057102dbb746593a7d59cf377c969b62e38c664Jae Seo         */
9956057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(String inputId, TvContentRating rating) {
9966057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
9976057102dbb746593a7d59cf377c969b62e38c664Jae Seo
9986057102dbb746593a7d59cf377c969b62e38c664Jae Seo        /**
999b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * This is invoked when a custom event from the bound TV input is sent to this view.
1000b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         *
10016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
1002b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param eventType The type of the event.
1003b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @param eventArgs Optional arguments of the event.
1004b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         * @hide
1005b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo         */
100615bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
1007b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        public void onEvent(String inputId, String eventType, Bundle eventArgs) {
1008b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        }
10096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
10106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
10116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * This is called when the time shift status is changed.
10126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
10136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param inputId The ID of the TV input bound to this view.
1014465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @param status The current time shift status. Should be one of the followings.
10156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <ul>
1016465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
10176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
1018465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
10196f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * </ul>
10206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
10213b9be6700fd631e25559693820d03389f8de3893Jae Seo        public void onTimeShiftStatusChanged(
10223b9be6700fd631e25559693820d03389f8de3893Jae Seo                String inputId, @TvInputManager.TimeShiftStatus int status) {
10236f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
1024b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    }
1025b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo
1026b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
10276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     * Interface definition for a callback to be invoked when the unhandled input event is received.
10286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo     */
10296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    public interface OnUnhandledInputEventListener {
10306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
10316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Called when an input event was not handled by the bound TV input.
10320610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         *
10330610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         * <p>This is called asynchronously from where the event is dispatched. It gives the host
10346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * application a chance to handle the unhandled input events.
10356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
10366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param event The input event.
10376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @return If you handled the event, return {@code true}. If you want to allow the event to
10386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         be handled by the next receiver, return {@code false}.
10396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
10406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        boolean onUnhandledInputEvent(InputEvent event);
10416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo    }
10426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
10432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private class MySessionCallback extends SessionCallback {
1044b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        final String mInputId;
1045b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo        Uri mChannelUri;
10461a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        Bundle mTuneParams;
1047a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        Uri mRecordedProgramUri;
10489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
10491a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        MySessionCallback(String inputId, Uri channelUri, Bundle tuneParams) {
1050b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            mInputId = inputId;
1051b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            mChannelUri = channelUri;
10521a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            mTuneParams = tuneParams;
10539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
10549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
1055a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        MySessionCallback(String inputId, Uri recordedProgramUri) {
1056a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mInputId = inputId;
1057a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mRecordedProgramUri = recordedProgramUri;
1058a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
1059a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
10609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
10619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void onSessionCreated(Session session) {
10626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
10636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onSessionCreated()");
10646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
10652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (this != mSessionCallback) {
10666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionCreated - session already created");
10679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // This callback is obsolete.
1068c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                if (session != null) {
1069c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                    session.release();
1070c31c450f5dd1436189fc4ac7a1ae26ef2fb19798Youngsang Cho                }
10719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                return;
10729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
10739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            mSession = session;
10749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (session != null) {
1075411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                // Sends the pending app private commands first.
1076411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                for (Pair<String, Bundle> command : mPendingAppPrivateCommands) {
1077411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                    mSession.sendAppPrivateCommand(command.first, command.second);
1078411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                }
1079411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo                mPendingAppPrivateCommands.clear();
1080411d58d330eafb093fe7edfa3fcccfadfc470076Jae Seo
10814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (sMainTvViewLock) {
1082c7f440dcd86ae88fc1b51e4394d66e4e80c9e53eJi-Hwan Lee                    if (hasWindowFocus() && TvView.this == sMainTvView.get()) {
108315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        mSession.setMain();
10844c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
10854c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
10869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // mSurface may not be ready yet as soon as starting an application.
10879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // In the case, we don't send Session.setSurface(null) unnecessarily.
10889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                // setSessionSurface will be called in surfaceCreated.
10899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                if (mSurface != null) {
10909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    setSessionSurface(mSurface);
1091e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    if (mSurfaceChanged) {
1092e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
1093e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
10949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
10959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                createSessionOverlayView();
10961da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                if (mStreamVolume != null) {
1097336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang                    mSession.setStreamVolume(mStreamVolume);
1098336cdf20dd44ee93b5173be73e26e966a2609eb0Dongwon Kang                }
10991da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                if (mCaptionEnabled != null) {
11001da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                    mSession.setCaptionEnabled(mCaptionEnabled);
11011da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo                }
1102a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                if (mChannelUri != null) {
1103a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSession.tune(mChannelUri, mTuneParams);
1104a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                } else {
1105a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSession.timeShiftPlay(mRecordedProgramUri);
1106a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1107465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                ensurePositionTracking();
1108b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo            } else {
11097cf67054550e8e6ea2379d7b0f0653796ce85062Youngsang Cho                mSessionCallback = null;
11102778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                if (mCallback != null) {
11112778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onConnectionFailed(mInputId);
1112b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo                }
11139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
11149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
11152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
11162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
11172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionReleased(Session session) {
11186320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onSessionReleased()");
11206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1121e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
11226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionReleased - session not created");
1123e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
11241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
1125ffad70bb7efe08ab8f03cb93e783714232a101acChulwoo Lee            mOverlayViewCreated = false;
1126ffad70bb7efe08ab8f03cb93e783714232a101acChulwoo Lee            mOverlayViewFrame = null;
1127e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            mSessionCallback = null;
11282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSession = null;
11292778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11302778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onDisconnected(mInputId);
11312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
11322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
1133832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
1134832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        @Override
11351f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(Session session, Uri channelUri) {
1136a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            if (DEBUG) {
11371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Log.d(TAG, "onChannelChangedByTvInput(" + channelUri + ")");
1138a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
11396320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
11406320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onChannelRetuned - session not created");
11416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
11426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11432778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11442778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onChannelRetuned(mInputId, channelUri);
1145a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
1146a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang        }
1147a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
1148a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang        @Override
114910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(Session session, List<TvTrackInfo> tracks) {
11506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onTracksChanged(" + tracks + ")");
11526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11531f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            if (this != mSessionCallback) {
11546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onTracksChanged - session not created");
11551f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                return;
1156832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
11572778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11582778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onTracksChanged(mInputId, tracks);
1159b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
1160b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
1161b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
11626057102dbb746593a7d59cf377c969b62e38c664Jae Seo        @Override
116310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(Session session, int type, String trackId) {
11646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
11666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1167d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            if (this != mSessionCallback) {
11686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onTrackSelected - session not created");
1169d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                return;
1170d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
11712778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
11722778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onTrackSelected(mInputId, type, trackId);
1173d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
1174d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
1175d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
1176d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        @Override
11776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(Session session, int width, int height) {
11786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
11796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onVideoSizeChanged()");
11806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1181e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
11826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoSizeChanged - session not created");
1183e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1184e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
11856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (mCallback != null) {
11866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mCallback.onVideoSizeChanged(mInputId, width, height);
11876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
11896320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
11906320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        @Override
11916320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoAvailable(Session session) {
11929b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            if (DEBUG) {
11939b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                Log.d(TAG, "onVideoAvailable()");
11949b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
11956320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
11966320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoAvailable - session not created");
11976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
11986320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
11992778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12002778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onVideoAvailable(mInputId);
12019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
12029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
12039b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
12046057102dbb746593a7d59cf377c969b62e38c664Jae Seo        @Override
12059b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoUnavailable(Session session, int reason) {
12066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
12076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onVideoUnavailable(reason=" + reason + ")");
12086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1209e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (this != mSessionCallback) {
12106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onVideoUnavailable - session not created");
1211e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1212e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
12132778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12142778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onVideoUnavailable(mInputId, reason);
12159b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
12169b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
12179b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
1218b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        @Override
1219bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(Session session) {
1220bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            if (DEBUG) {
1221bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                Log.d(TAG, "onContentAllowed()");
1222bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
12236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onContentAllowed - session not created");
12256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
12272778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12282778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onContentAllowed(mInputId);
1229bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
1230bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
1231bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
1232bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        @Override
12336057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(Session session, TvContentRating rating) {
12346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (DEBUG) {
12356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.d(TAG, "onContentBlocked(rating=" + rating + ")");
12366320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1237774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee            if (this != mSessionCallback) {
12386320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onContentBlocked - session not created");
1239774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee                return;
1240774f6c3657dff9f05ffd90d9a4a90153d06180e1Ji-Hwan Lee            }
12412778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12422778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onContentBlocked(mInputId, rating);
12436057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
12446057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
12456057102dbb746593a7d59cf377c969b62e38c664Jae Seo
1246bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        @Override
1247ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
1248ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            if (DEBUG) {
1249ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                Log.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top + ", right="
1250ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        + right + ", bottom=" + bottom + ",)");
1251ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
12526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onLayoutSurface - session not created");
12546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
1256ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewLeft = left;
1257ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewTop = top;
1258ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewRight = right;
1259ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mSurfaceViewBottom = bottom;
1260ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mUseRequestedSurfaceLayout = true;
1261ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            requestLayout();
1262ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
1263ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
1264ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        @Override
1265903d6b72cd572665309633e925485464d08bb25aJaewan Kim        public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
1266903d6b72cd572665309633e925485464d08bb25aJaewan Kim            if (DEBUG) {
1267903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Log.d(TAG, "onSessionEvent(" + eventType + ")");
1268903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
12696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            if (this != mSessionCallback) {
12706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                Log.w(TAG, "onSessionEvent - session not created");
12716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return;
12726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
12732778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            if (mCallback != null) {
12742778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                mCallback.onEvent(mInputId, eventType, eventArgs);
1275832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
1276832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
12776f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
12786f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
12796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStatusChanged(Session session, int status) {
12806f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
12816f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftStatusChanged()");
12826f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12836f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
12846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftStatusChanged - session not created");
12856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
12866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mCallback != null) {
12886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                mCallback.onTimeShiftStatusChanged(mInputId, status);
12896f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12906f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
12916f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
12926f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
12936f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
12946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
12956f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftStartPositionChanged()");
12966f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
12976f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
12986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftStartPositionChanged - session not created");
12996f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
13006f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
1301465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo            if (mTimeShiftPositionCallback != null) {
1302465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                mTimeShiftPositionCallback.onTimeShiftStartPositionChanged(mInputId, timeMs);
13036f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13046f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
13056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
13066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        @Override
13076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
13086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (DEBUG) {
13096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.d(TAG, "onTimeShiftCurrentPositionChanged()");
13106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (this != mSessionCallback) {
13126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "onTimeShiftCurrentPositionChanged - session not created");
13136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
13146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
1315465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo            if (mTimeShiftPositionCallback != null) {
1316465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                mTimeShiftPositionCallback.onTimeShiftCurrentPositionChanged(mInputId, timeMs);
13176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
13186f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
13199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho    }
13209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho}
1321