TvInputManager.java revision 4e389e557efb7806b73d2059d46e2809c1a9f83d
13957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/*
23957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Copyright (C) 2014 The Android Open Source Project
33957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
43957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Licensed under the Apache License, Version 2.0 (the "License");
53957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * you may not use this file except in compliance with the License.
63957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * You may obtain a copy of the License at
73957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
83957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *      http://www.apache.org/licenses/LICENSE-2.0
93957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Unless required by applicable law or agreed to in writing, software
113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * distributed under the License is distributed on an "AS IS" BASIS,
123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * See the License for the specific language governing permissions and
143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * limitations under the License.
153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */
163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seopackage android.media.tv;
183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19a759b111a1c9cb00284038f8a1554bf29709b952Jae Seoimport android.annotation.SystemApi;
209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
22832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Handler;
243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.os.Looper;
266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.os.Message;
273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
28969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.util.ArrayMap;
293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.Log;
306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.util.Pools.Pool;
316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.util.Pools.SimplePool;
323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEvent;
356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEventSender;
36d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kimimport android.view.KeyEvent;
373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.View;
393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Iterator;
42969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport java.util.LinkedList;
433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/**
473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Central system API to the overall TV input framework (TIF) architecture, which arbitrates
483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * interaction between applications and the selected TV inputs.
493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */
503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManager {
513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManager";
523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
536057102dbb746593a7d59cf377c969b62e38c664Jae Seo    static final int VIDEO_UNAVAILABLE_REASON_START = 0;
546057102dbb746593a7d59cf377c969b62e38c664Jae Seo    static final int VIDEO_UNAVAILABLE_REASON_END = 3;
556057102dbb746593a7d59cf377c969b62e38c664Jae Seo
569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     * A generic reason. Video is not available due to an unspecified error.
589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
596057102dbb746593a7d59cf377c969b62e38c664Jae Seo    public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = VIDEO_UNAVAILABLE_REASON_START;
609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
616e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo     * Video is not available because the TV input is in the middle of tuning to a new channel.
629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
636e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo    public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1;
649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     * Video is not available due to the weak TV signal.
669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2;
689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     * Video is not available because the TV input stopped the playback temporarily to buffer more
709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     * data.
719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
726057102dbb746593a7d59cf377c969b62e38c664Jae Seo    public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = VIDEO_UNAVAILABLE_REASON_END;
739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
74969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
75969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is connected.
76969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
77969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
782778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
79969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
80969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
81969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED = 0;
82969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
83969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is connected but in standby mode. It would take a while until it becomes
84969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * fully ready.
85969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
86969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
872778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
88969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
89969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
90969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED_STANDBY = 1;
91969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
92969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is disconnected.
93969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
94969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
952778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
96969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
97969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
98969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_DISCONNECTED = 2;
99969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
100783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
101783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the user blocked content ratings change. For use with the
102783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isRatingBlocked}.
103783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
104783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_BLOCKED_RATINGS_CHANGED =
1052778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
106783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
107783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
108783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the parental controls enabled state changes. For use with the
109783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isParentalControlsEnabled}.
110783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
111783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED =
1122778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
1139c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
1149c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
1159c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Broadcast intent action used to query available content rating systems.
1169c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p>
1179c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * The TV input manager service locates available content rating systems by querying broadcast
1189c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * receivers that are registered for this action. An application can offer additional content
1199c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * rating systems to the user by declaring a suitable broadcast receiver in its manifest.
1209c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p><p>
1219c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Here is an example broadcast receiver declaration that an application might include in its
1229c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * AndroidManifest.xml to advertise custom content rating systems. The meta-data specifies a
1239c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * resource that contains a description of each content rating system that is provided by the
1249c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * application.
1259c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p><pre class="prettyprint">
1269c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * {@literal
1279c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <receiver android:name=".TvInputReceiver">
1289c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <intent-filter>
1299c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *         <action android:name=
1304e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *                 "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
1319c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     </intent-filter>
1329c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <meta-data
1334e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *             android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
1349c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *             android:resource="@xml/tv_content_rating_systems" />
1359c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </receiver>}</pre></p>
1369c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * In the above example, the <code>@xml/tv_content_rating_systems</code> resource refers to an
1379c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * XML resource whose root element is <code>&lt;rating-system-definitions&gt;</code> that
1389c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * contains zero or more <code>&lt;rating-system-definition&gt;</code> elements. Each <code>
1399c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * &lt;rating-system-definition&gt;</code> element specifies the ratings, sub-ratings and rating
1409c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * orders of a particular content rating system.
1419c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p>
1429c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *
1439c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * @see TvContentRating
1449c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
1459c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String ACTION_QUERY_CONTENT_RATING_SYSTEMS =
1462778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
1479c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
1489c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
1499c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Content rating systems metadata associated with {@link #ACTION_QUERY_CONTENT_RATING_SYSTEMS}.
1509c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p>
1519c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Specifies the resource ID of an XML resource that describes the content rating systems that
1529c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * are provided by the application.
1539c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p>
1549c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
1559c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String META_DATA_CONTENT_RATING_SYSTEMS =
1562778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
157783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputManager mService;
1593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
160969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private final Object mLock = new Object();
161969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
1632778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private final List<TvInputCallbackRecord> mCallbackRecords =
1642778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            new LinkedList<TvInputCallbackRecord>();
165969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
166969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    // A mapping from TV input ID to the state of corresponding input.
1676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
168969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private final Map<String, Integer> mStateMap = new ArrayMap<String, Integer>();
1693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // A mapping from the sequence number of a session to its SessionCallbackRecord.
1712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
1722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            new SparseArray<SessionCallbackRecord>();
1733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A sequence number for the next session to be created. Should be protected by a lock
1752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // {@code mSessionCallbackRecordMap}.
1763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mNextSeq;
1773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputClient mClient;
1793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1802778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private final ITvInputManagerCallback mManagerCallback;
181969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final int mUserId;
1833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Interface used to receive the created session.
186b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
18815bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
1892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    public abstract static class SessionCallback {
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * This is called after {@link TvInputManager#createSession} has been processed.
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param session A {@link TvInputManager.Session} instance created. This can be
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *            {@code null} if the creation request failed.
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionCreated(Session session) {
1972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
1982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        /**
2002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This is called when {@link TvInputManager.Session} is released.
2012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This typically happens when the process hosting the session has crashed or been killed.
2022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         *
2032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * @param session A {@link TvInputManager.Session} instance released.
2042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         */
2052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionReleased(Session session) {
2062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
207832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
208832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
2091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the channel of this session is changed by the underlying TV input
2106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * without any {@link TvInputManager.Session#tune(Uri)} request.
211a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         *
212d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param channelUri The URI of a channel.
214a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         */
2151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(Session session, Uri channelUri) {
216832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
217832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
218832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
2191f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the track information of the session has been changed.
220b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         *
221d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param tracks A list which includes track information.
223b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         */
22410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(Session session, List<TvTrackInfo> tracks) {
225b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
226b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
227b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        /**
22810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * This is called when a track for a given type is selected.
2299b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
2306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
23110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the selected track. The type can be
23210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
23310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
23410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the selected track. When {@code null} the currently selected
23510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track for a given type should be unselected.
236d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
23710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(Session session, int type, String trackId) {
238d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
239d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
240d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
2416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * This is invoked when the video size has been changed. It is also called when the first
2426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * time video size information becomes available after the session is tuned to a specific
2436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * channel.
2446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         *
2456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param width The width of the video.
2476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param height The height of the video.
2486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
2496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(Session session, int width, int height) {
2506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
2516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
2526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
253d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * This is called when the video is available, so the TV input starts the playback.
254d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         *
255d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
2579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoAvailable(Session session) {
2589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
2599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
2609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
2619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is not available, so the TV input stops the playback.
2629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
2639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback
2649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param reason The reason why the TV input stopped the playback:
2659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <ul>
2669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
2676e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
2689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
2699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
2709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * </ul>
2719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
2729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoUnavailable(Session session, int reason) {
2739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
2749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
2759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
276bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be allowed to watch since
277bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * its content rating is not blocked by parental controls.
278bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         *
279bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback
280bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         */
281bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(Session session) {
282bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
283bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
284bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        /**
285bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be not allowed to watch
286bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * since its content rating is blocked by parental controls.
2876057102dbb746593a7d59cf377c969b62e38c664Jae Seo         *
2886057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback
2896057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param rating The content ration of the blocked program.
2906057102dbb746593a7d59cf377c969b62e38c664Jae Seo         */
2916057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(Session session, TvContentRating rating) {
2926057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
2936057102dbb746593a7d59cf377c969b62e38c664Jae Seo
2946057102dbb746593a7d59cf377c969b62e38c664Jae Seo        /**
2955b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * This is called when {@link TvInputService.Session#layoutSurface} is called to change the
2965b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * layout of surface.
297ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         *
298ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         * @param session A {@link TvInputManager.Session} associated with this callback
2995b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param left Left position.
3005b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param top Top position.
3015b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param right Right position.
3025b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param bottom Bottom position.
303ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         * @hide
304ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         */
305ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        @SystemApi
306ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
307ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
308ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
309ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        /**
310832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * This is called when a custom event has been sent from this session.
311832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         *
312832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param session A {@link TvInputManager.Session} associated with this callback
313832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventType The type of the event.
314832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventArgs Optional arguments of the event.
315832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @hide
316832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         */
31715bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
318832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
319832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private static final class SessionCallbackRecord {
3232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SessionCallback mSessionCallback;
3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
3252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session mSession;
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        SessionCallbackRecord(SessionCallback sessionCallback,
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Handler handler) {
3292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallback = sessionCallback;
3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionCreated(final Session session) {
3342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSession = session;
3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
3382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionCreated(session);
3392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
3402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            });
3412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
3422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionReleased() {
3442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mHandler.post(new Runnable() {
3452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                @Override
3462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                public void run() {
3472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionReleased(mSession);
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
351832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
3526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postChannelRetuned(final Uri channelUri) {
353832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
354832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
355832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
3561f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    mSessionCallback.onChannelRetuned(mSession, channelUri);
357832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
358832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
359832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
360832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
3616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTracksChanged(final List<TvTrackInfo> tracks) {
362b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            mHandler.post(new Runnable() {
363b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                @Override
364b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                public void run() {
36510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTracksChanged(mSession, tracks);
366b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
367b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            });
368b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
369b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
3706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTrackSelected(final int type, final String trackId) {
371d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            mHandler.post(new Runnable() {
372d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                @Override
373d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                public void run() {
37410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTrackSelected(mSession, type, trackId);
375d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
376d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            });
377d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
378d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
3796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoSizeChanged(final int width, final int height) {
3806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            mHandler.post(new Runnable() {
3816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                @Override
3826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                public void run() {
3836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSessionCallback.onVideoSizeChanged(mSession, width, height);
3846320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
3856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            });
3866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
3876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
3886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoAvailable() {
3899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
3909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
3919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
3929b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoAvailable(mSession);
3939b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
3949b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
3959b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
3969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
3976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoUnavailable(final int reason) {
3989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
3999b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
4009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
4019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoUnavailable(mSession, reason);
4029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
4039b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
4049b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
4059b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
4066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentAllowed() {
407bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            mHandler.post(new Runnable() {
408bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                @Override
409bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                public void run() {
410bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    mSessionCallback.onContentAllowed(mSession);
411bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
412bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            });
413bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
414bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
4156320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentBlocked(final TvContentRating rating) {
4166057102dbb746593a7d59cf377c969b62e38c664Jae Seo            mHandler.post(new Runnable() {
4176057102dbb746593a7d59cf377c969b62e38c664Jae Seo                @Override
4186057102dbb746593a7d59cf377c969b62e38c664Jae Seo                public void run() {
4196057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    mSessionCallback.onContentBlocked(mSession, rating);
4206057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
4216057102dbb746593a7d59cf377c969b62e38c664Jae Seo            });
4226057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
4236057102dbb746593a7d59cf377c969b62e38c664Jae Seo
4246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postLayoutSurface(final int left, final int top, final int right,
425ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                final int bottom) {
426ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mHandler.post(new Runnable() {
427ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                @Override
428ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                public void run() {
429ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    mSessionCallback.onLayoutSurface(mSession, left, top, right, bottom);
430ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
431ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            });
432ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
433ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
4346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionEvent(final String eventType, final Bundle eventArgs) {
435832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
436832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
437832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
438832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    mSessionCallback.onSessionEvent(mSession, eventType, eventArgs);
439832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
440832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
441832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
4452778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Callback used to monitor status of the TV input.
4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
4472778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public abstract static class TvInputCallback {
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
449969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * This is called when the state of a given TV input is changed.
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
4518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param state State of the TV input. The value is one of the following:
453969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <ul>
454969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED}
455969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY}
456969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_DISCONNECTED}
457969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * </ul>
4583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
459969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void onInputStateChanged(String inputId, int state) {
4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4618e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
4628e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
4638e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * This is called when a TV input is added.
4648e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
4658e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4668e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
4678e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputAdded(String inputId) {
4688e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
4698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
4708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
4718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * This is called when a TV input is removed.
4728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
4738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
4758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputRemoved(String inputId) {
4768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
47719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
47819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        /**
47919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * This is called when a TV input is updated. The update of TV input happens when it is
48019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * reinstalled or the media on which the newer version of TV input exists is
48119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * available/unavailable.
48219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         *
48319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * @param inputId The id of the TV input.
48419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * @hide
48519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         */
48619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        @SystemApi
48719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        public void onInputUpdated(String inputId) {
48819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
4893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4912778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private static final class TvInputCallbackRecord {
4922778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        private final TvInputCallback mCallback;
4933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4952778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallbackRecord(TvInputCallback callback, Handler handler) {
4962778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallback = callback;
4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5002778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallback getCallback() {
5012778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            return mCallback;
5028e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
5038e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
5048e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputStateChanged(final String inputId, final int state) {
5058e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
5068e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
5078e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
5082778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputStateChanged(inputId, state);
5098e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
5108e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
5118e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
5128e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
5138e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputAdded(final String inputId) {
5148e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
5158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
5168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
5172778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputAdded(inputId);
5188e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
5198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
5203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5228e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputRemoved(final String inputId) {
5233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
5243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
5262778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputRemoved(inputId);
5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
53019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
53119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        public void postInputUpdated(final String inputId) {
53219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            mHandler.post(new Runnable() {
53319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                @Override
53419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                public void run() {
535db8f7ab752de641b147015a2b4a134913fbcb594Youngsang Cho                    mCallback.onInputUpdated(inputId);
53619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
53719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            });
53819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
5393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
542d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Interface used to receive events from Hardware objects.
543d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
544d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
545d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
546d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public abstract static class HardwareCallback {
547d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onReleased();
548d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
549d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
550d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
551d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @hide
5533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
5543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManager(ITvInputManager service, int userId) {
5553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mService = service;
5563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mUserId = userId;
5573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mClient = new ITvInputClient.Stub() {
5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
559d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
5606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    int seq) {
5612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
5622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (record == null) {
5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "Callback not found for " + token);
5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Session session = null;
5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (token != null) {
5692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        session = new Session(token, channel, mService, mUserId, seq,
5702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                                mSessionCallbackRecordMap);
5713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    record.postSessionCreated(session);
5733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
5772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            public void onSessionReleased(int seq) {
5782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
5792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
5802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallbackRecordMap.delete(seq);
5812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (record == null) {
5822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Log.e(TAG, "Callback not found for seq:" + seq);
5832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
5842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
5852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.mSession.releaseInternal();
5862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.postSessionReleased();
5872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
5882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
5892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
5902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            @Override
5911f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri, int seq) {
592a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mSessionCallbackRecordMap) {
593a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
594a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (record == null) {
595a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
596a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
597a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
5981f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    record.postChannelRetuned(channelUri);
599a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
600a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
601a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
602a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
60310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks, int seq) {
604832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
605832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
606832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
607832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
608832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
609832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
6106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTracks(tracks)) {
6116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTracksChanged(tracks);
6126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
6136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
614b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
615b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
616b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
617b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
61810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId, int seq) {
619d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mSessionCallbackRecordMap) {
620d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
621d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (record == null) {
622d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
623d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
624d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
6256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTrackSelection(type, trackId)) {
6266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTrackSelected(type, trackId);
6276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
6286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
6296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
6306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
6316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
6326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            private void postVideoSizeChangedIfNeededLocked(SessionCallbackRecord record) {
6336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                TvTrackInfo track = record.mSession.getVideoTrackToNotify();
6346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (track != null) {
6356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    record.postVideoSizeChanged(track.getVideoWidth(), track.getVideoHeight());
636d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
637d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
638d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
639d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
6409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable(int seq) {
6419b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
6429b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6439b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
6449b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
6459b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6469b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6479b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoAvailable();
6489b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6499b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6509b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6519b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
6529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason, int seq) {
6539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
6549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
6569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
6579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoUnavailable(reason);
6609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
664bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed(int seq) {
665bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mSessionCallbackRecordMap) {
666bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
667bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (record == null) {
668bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
669bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
670bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
671bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    record.postContentAllowed();
672bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
673bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
674bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
675bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6766057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating, int seq) {
6776057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mSessionCallbackRecordMap) {
6786057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6796057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (record == null) {
6806057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
6816057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6826057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6836057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    record.postContentBlocked(TvContentRating.unflattenFromString(rating));
6846057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6856057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6866057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6876057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
688ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom, int seq) {
689ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mSessionCallbackRecordMap) {
690ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
691ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (record == null) {
692ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
693ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
694ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
695ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    record.postLayoutSurface(left, top, right, bottom);
696ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
697ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
698ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
699ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
700832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs, int seq) {
701832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
702832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
703832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
704832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
705832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
706832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
707832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    record.postSessionEvent(eventType, eventArgs);
708832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
709832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
710969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        };
7112778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        mManagerCallback = new ITvInputManagerCallback.Stub() {
712832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
713969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            public void onInputStateChanged(String inputId, int state) {
714969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                synchronized (mLock) {
715969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    mStateMap.put(inputId, state);
7162778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7178e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputStateChanged(inputId, state);
7188e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
7198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
7208e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7218e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7228e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
7238e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputAdded(String inputId) {
7248e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
7258e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.put(inputId, INPUT_STATE_CONNECTED);
7262778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7278e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputAdded(inputId);
7288e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
7298e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
7308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7318e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7328e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
7338e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputRemoved(String inputId) {
7348e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
7358e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.remove(inputId);
7362778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputRemoved(inputId);
7383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
7393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
7403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
74119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
74219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
74319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onInputUpdated(String inputId) {
74419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                synchronized (mLock) {
745db8f7ab752de641b147015a2b4a134913fbcb594Youngsang Cho                    for (TvInputCallbackRecord record : mCallbackRecords) {
74619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                        record.postInputUpdated(inputId);
74719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    }
74819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
74919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
7503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
751969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        try {
7529127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            if (mService != null) {
7539127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo                mService.registerCallback(mManagerCallback, mUserId);
7549127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            }
755969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } catch (RemoteException e) {
756969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            Log.e(TAG, "mService.registerCallback failed: " + e);
757969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
7583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
7613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Returns the complete list of TV inputs on the system.
7623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
7633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @return List of {@link TvInputInfo} for each TV input that describes its meta information.
7643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
7653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public List<TvInputInfo> getTvInputList() {
7663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
7673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return mService.getTvInputList(mUserId);
7683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
7693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new RuntimeException(e);
7703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
774b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * Returns the {@link TvInputInfo} for a given TV input.
775b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     *
776b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @param inputId The ID of the TV input.
777b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @return the {@link TvInputInfo} for a given TV input. {@code null} if not found.
778b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     */
779b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    public TvInputInfo getTvInputInfo(String inputId) {
780783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (inputId == null) {
781783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("inputId cannot be null");
782783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
783b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        try {
784b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            return mService.getTvInputInfo(inputId, mUserId);
785b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        } catch (RemoteException e) {
786b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            throw new RuntimeException(e);
787b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
788b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    }
789b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
790b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    /**
7916320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo     * Returns the state of a given TV input. It returns one of the following:
792969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <ul>
793969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED}
794969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED_STANDBY}
795969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_DISCONNECTED}
796969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </ul>
7973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
7988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param inputId The id of the TV input.
799969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * @throws IllegalArgumentException if the argument is {@code null} or if there is no
800969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     *        {@link TvInputInfo} corresponding to {@code inputId}.
8013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
802969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public int getInputState(String inputId) {
803d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (inputId == null) {
804783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("inputId cannot be null");
8053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
806969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
807969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            Integer state = mStateMap.get(inputId);
808969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (state == null) {
809969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throw new IllegalArgumentException("Unrecognized input ID: " + inputId);
8103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
811969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return state.intValue();
8123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
8162778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Registers a {@link TvInputCallback}.
8173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
8182778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback A callback used to monitor status of the TV inputs.
8198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the status change will be delivered to.
8203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
8213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
8222778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public void registerCallback(TvInputCallback callback, Handler handler) {
8232778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        if (callback == null) {
8248e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            throw new IllegalArgumentException("callback cannot be null");
8253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (handler == null) {
8273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("handler cannot be null");
8283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
829969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
8302778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallbackRecords.add(new TvInputCallbackRecord(callback, handler));
8313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
8352778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Unregisters the existing {@link TvInputCallback}.
8363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
8372778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback The existing callback to remove.
8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
8402778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public void unregisterCallback(final TvInputCallback callback) {
8412778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        if (callback == null) {
8428e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            throw new IllegalArgumentException("callback cannot be null");
8433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
844969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
8452778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            for (Iterator<TvInputCallbackRecord> it = mCallbackRecords.iterator();
846969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    it.hasNext(); ) {
8472778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                TvInputCallbackRecord record = it.next();
8482778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                if (record.getCallback() == callback) {
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    it.remove();
850969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    break;
8513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
857783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the user's parental controls enabled state.
858783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
859783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the user enabled the parental controls, {@code false} otherwise.
860783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
861783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public boolean isParentalControlsEnabled() {
862783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
863783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isParentalControlsEnabled(mUserId);
864783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
865783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
866783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
867783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
868783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
869783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
870783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Sets the user's parental controls enabled state.
871783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
872783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param enabled The user's parental controls enabled state. {@code true} if the user enabled
873783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *            the parental controls, {@code false} otherwise.
874783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isParentalControlsEnabled
875783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
876783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
877783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
878783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void setParentalControlsEnabled(boolean enabled) {
879783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
880783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.setParentalControlsEnabled(enabled, mUserId);
881783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
882783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
883783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
884783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
885783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
886783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
887783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Checks whether a given TV content rating is blocked by the user.
888783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
889783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The TV content rating to check.
890783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the given TV content rating is blocked, {@code false} otherwise.
891783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
892783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public boolean isRatingBlocked(TvContentRating rating) {
893783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
894783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
895783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
896783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
897783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isRatingBlocked(rating.flattenToString(), mUserId);
898783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
899783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
900783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
901783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
902783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
903783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
904783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the list of blocked content ratings.
905783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
906783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return the list of content ratings blocked by the user.
907783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
908783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
909783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
910783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public List<TvContentRating> getBlockedRatings() {
911783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
912783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            List<TvContentRating> ratings = new ArrayList<TvContentRating>();
913783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            for (String rating : mService.getBlockedRatings(mUserId)) {
914783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                ratings.add(TvContentRating.unflattenFromString(rating));
915783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
916783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return ratings;
917783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
918783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
919783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
920783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
921783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
922783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
923783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Adds a user blocked content rating.
924783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
925783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to block.
926783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
927783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #removeBlockedRating
928783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
929783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
930783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
931783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void addBlockedRating(TvContentRating rating) {
932783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
933783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
934783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
935783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
936783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.addBlockedRating(rating.flattenToString(), mUserId);
937783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
938783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
939783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
940783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
941783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
942783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Removes a user blocked content rating.
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to unblock.
946783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
947783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #addBlockedRating
948783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
949783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
950783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
951783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void removeBlockedRating(TvContentRating rating) {
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
955783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
956783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.removeBlockedRating(rating.flattenToString(), mUserId);
957783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
958783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
959783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
960783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
961783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
962783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
9639c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Returns the list of all TV content rating systems defined.
9645c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     * @hide
9655c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     */
9665c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    @SystemApi
9679c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
9685c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        try {
9699c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            return mService.getTvContentRatingSystemList(mUserId);
9705c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        } catch (RemoteException e) {
9715c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            throw new RuntimeException(e);
9725c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
9735c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    }
9745c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
9755c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    /**
976674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho     * Creates a {@link Session} for a given TV input.
9773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * <p>
9783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * The number of sessions that can be created at the same time is limited by the capability of
9793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * the given TV input.
9803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * </p>
9813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
9828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param inputId The id of the TV input.
9838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param callback A callback used to receive the created session.
9848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the session creation will be delivered to.
9853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
986b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
9873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
98815bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
9892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    public void createSession(String inputId, final SessionCallback callback,
9903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Handler handler) {
991d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (inputId == null) {
992d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            throw new IllegalArgumentException("id cannot be null");
9933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (callback == null) {
9953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("callback cannot be null");
9963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (handler == null) {
9983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("handler cannot be null");
9993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionCallbackRecord record = new SessionCallbackRecord(callback, handler);
10012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        synchronized (mSessionCallbackRecordMap) {
10023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            int seq = mNextSeq++;
10032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap.put(seq, record);
10043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
1005d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mService.createSession(mClient, inputId, seq, mUserId);
10063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
10073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
10083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
10113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1012b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
1013c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Returns the TvStreamConfig list of the given TV input.
1014c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
101590e733385d466acd87730676c83c080a17ff495fWonsik Kim     * If you are using {@link Hardware} object from {@link
101690e733385d466acd87730676c83c080a17ff495fWonsik Kim     * #acquireTvInputHardware}, you should get the list of available streams
101790e733385d466acd87730676c83c080a17ff495fWonsik Kim     * from {@link HardwareCallback#onStreamConfigChanged} method, not from
101890e733385d466acd87730676c83c080a17ff495fWonsik Kim     * here. This method is designed to be used with {@link #captureFrame} in
101990e733385d466acd87730676c83c080a17ff495fWonsik Kim     * capture scenarios specifically and not suitable for any other use.
102090e733385d466acd87730676c83c080a17ff495fWonsik Kim     *
1021c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param inputId the id of the TV input.
1022c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return List of {@link TvStreamConfig} which is available for capturing
1023c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *   of the given TV input.
1024c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1025c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1026c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1027c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
1028c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1029c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.getAvailableTvStreamConfigList(inputId, mUserId);
1030c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1031c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            throw new RuntimeException(e);
1032c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1033c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1034c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1035c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1036c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Take a snapshot of the given TV input into the provided Surface.
1037c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
1038c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param inputId the id of the TV input.
1039c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param surface the {@link Surface} to which the snapshot is captured.
1040c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param config the {@link TvStreamConfig} which is used for capturing.
1041c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return true when the {@link Surface} is ready to be captured.
1042c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1043c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1044c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1045c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
1046c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1047c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.captureFrame(inputId, surface, config, mUserId);
1048c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1049c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            throw new RuntimeException(e);
1050df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1051df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    }
1052df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1053df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    /**
1054df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * Returns true if there is only a single TV input session.
1055df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     *
1056df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * @hide
1057df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     */
1058df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    @SystemApi
1059df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    public boolean isSingleSessionActive() {
1060df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        try {
1061df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            return mService.isSingleSessionActive(mUserId);
1062df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        } catch (RemoteException e) {
1063df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            throw new RuntimeException(e);
1064c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1065c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1066c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1067c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1068d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Returns a list of TvInputHardwareInfo objects representing available hardware.
1069d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1070d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1071d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1072d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1073d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public List<TvInputHardwareInfo> getHardwareList() {
1074d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1075d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mService.getHardwareList();
1076d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1077d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1078d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1079d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1080d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1081d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1082d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Returns acquired TvInputManager.Hardware object for given deviceId.
1083d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1084d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * If there are other Hardware object acquired for the same deviceId, calling this method will
1085d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
1086d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * old object.
1087d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1088d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1089d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1090d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1091d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
1092d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            TvInputInfo info) {
1093d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1094d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return new Hardware(
1095d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
1096d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1097d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onReleased() {
1098d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onReleased();
1099d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1100d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1101d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1102d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onStreamConfigChanged(TvStreamConfig[] configs) {
1103d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onStreamConfigChanged(configs);
1104d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1105d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }, info, mUserId));
1106d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1107d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1108d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1109d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1110d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1111d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1112d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Releases previously acquired hardware object.
1113d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1114d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1115d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1116d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1117d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public void releaseTvInputHardware(int deviceId, Hardware hardware) {
1118d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1119d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
1120d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1121d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1122d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1123d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1124d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1125d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1126b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * The Session provides the per-session functionality of TV inputs.
1127b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
1128b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
112915bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
11303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public static final class Session {
11316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_IN_PROGRESS = -1;
11326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_NOT_HANDLED = 0;
11336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_HANDLED = 1;
11346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
11366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ITvInputManager mService;
11383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
11392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mSeq;
11406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // For scheduling input event handling on the main thread. This also serves as a lock to
11426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // protect pending input events and the input channel.
11436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper());
11446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
11466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
11472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
11486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        private IBinder mToken;
11506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private TvInputEventSender mSender;
11516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private InputChannel mChannel;
11526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
11536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private final Object mTrackLock = new Object();
11546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
115510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mAudioTracks = new ArrayList<TvTrackInfo>();
11566320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
115710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mVideoTracks = new ArrayList<TvTrackInfo>();
11586320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
115910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mSubtitleTracks = new ArrayList<TvTrackInfo>();
11606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
116110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedAudioTrackId;
11626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
116310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedVideoTrackId;
11646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
116510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedSubtitleTrackId;
11666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
11676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoWidth;
11686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
11696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoHeight;
11703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
11722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
11733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mToken = token;
11746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mChannel = channel;
11753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mService = service;
11763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
11772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
11782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap = sessionCallbackRecordMap;
11793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
11823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Releases this session.
11833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
11843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void release() {
11859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1186dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1187dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
11889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
11893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.releaseSession(mToken, mUserId);
11913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
11923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
11933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            releaseInternal();
11963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
119915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * Sets this as the main session. The main session is a session whose corresponding TV
120015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * input determines the HDMI-CEC active source device.
120115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         *
120215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * @see TvView#setMain
12034c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee         */
120415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        void setMain() {
12054c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            if (mToken == null) {
12064c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Log.w(TAG, "The session has been already released");
12074c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                return;
12084c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
12094c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
12104c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                mService.setMainSession(mToken, mUserId);
12114c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } catch (RemoteException e) {
12124c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                throw new RuntimeException(e);
12134c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
12144c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
12154c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
12164c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        /**
12173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Sets the {@link android.view.Surface} for this session.
12183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
12193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param surface A {@link android.view.Surface} used to render video.
12203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1221f1c025cbcd98f2366d384c5aac114c330090a645Wonsik Kim        public void setSurface(Surface surface) {
12229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1223dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1224dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
12259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // surface can be null.
12273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setSurface(mToken, surface, mUserId);
12293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
12303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
12313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
1235e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * Notifies of any structural changes (format or size) of the {@link Surface}
1236e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * passed by {@link #setSurface}.
1237e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         *
1238e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param format The new PixelFormat of the {@link Surface}.
1239e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param width The new width of the {@link Surface}.
1240e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param height The new height of the {@link Surface}.
1241e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @hide
1242e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         */
124315bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
1244e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(int format, int width, int height) {
1245e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (mToken == null) {
1246e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Log.w(TAG, "The session has been already released");
1247e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1248e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1249e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1250e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
1251e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } catch (RemoteException e) {
1252e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                throw new RuntimeException(e);
1253e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1254e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1255e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1256e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        /**
1257782f7345471072b630e58c7abd3579b0015273b1Jae Seo         * Sets the relative stream volume of this session to handle a change of audio focus.
12583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
12593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param volume A volume value between 0.0f to 1.0f.
12603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @throws IllegalArgumentException if the volume value is out of range.
12613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1262782f7345471072b630e58c7abd3579b0015273b1Jae Seo        public void setStreamVolume(float volume) {
12639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1264dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1265dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
12669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (volume < 0.0f || volume > 1.0f) {
12693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    throw new IllegalArgumentException("volume should be between 0.0f and 1.0f");
12703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setVolume(mToken, volume, mUserId);
12723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
12733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
12743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
12783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Tunes to a given channel.
12793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
12803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param channelUri The URI of a channel.
12813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @throws IllegalArgumentException if the argument is {@code null}.
12823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
12833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(Uri channelUri) {
12841a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            tune(channelUri, null);
12851a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        }
12861a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
12871a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        /**
12881a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * Tunes to a given channel.
12891a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         *
12901a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param channelUri The URI of a channel.
12911a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param params A set of extra parameters which might be handled with this tune event.
12921a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @throws IllegalArgumentException if {@code channelUri} is {@code null}.
12931a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @hide
12941a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         */
12951a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        @SystemApi
12961a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(Uri channelUri, Bundle params) {
12973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (channelUri == null) {
12983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new IllegalArgumentException("channelUri cannot be null");
12993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
13009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1301dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1302dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
13039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
13056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
13066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
13076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
13086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedAudioTrackId = null;
13096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedVideoTrackId = null;
13106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedSubtitleTrackId = null;
13116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoWidth = 0;
13126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoHeight = 0;
13136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
13143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
13151a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mService.tune(mToken, channelUri, params, mUserId);
13163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
13173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
13183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
13193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
13209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
13222c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * Enables or disables the caption for this session.
13232c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         *
13242c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * @param enabled {@code true} to enable, {@code false} to disable.
13252c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         */
13262c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(boolean enabled) {
13272c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            if (mToken == null) {
13282c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Log.w(TAG, "The session has been already released");
13292c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                return;
13302c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13312c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
13322c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                mService.setCaptionEnabled(mToken, enabled, mUserId);
13332c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } catch (RemoteException e) {
13342c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                throw new RuntimeException(e);
13352c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13362c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
13372c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
13382c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        /**
13391f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Selects a track.
13401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
134110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the track to select. The type can be
134210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
134310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
134410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the track to select. When {@code null}, the currently selected
134510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track of the given type will be unselected.
13465b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @see #getTracks
13471f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
134810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(int type, String trackId) {
13496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
13506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
13516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mAudioTracks, trackId)) {
13526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid audio trackId: " + trackId);
13536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
13566320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mVideoTracks, trackId)) {
13576320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid video trackId: " + trackId);
13586320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13596320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
13616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mSubtitleTracks, trackId)) {
13626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid subtitle trackId: " + trackId);
13636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else {
13666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    throw new IllegalArgumentException("invalid type: " + type);
136710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
13681f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13691f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            if (mToken == null) {
13701f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Log.w(TAG, "The session has been already released");
13711f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                return;
13721f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13731f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
137410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                mService.selectTrack(mToken, type, trackId, mUserId);
13751f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } catch (RemoteException e) {
13761f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                throw new RuntimeException(e);
13771f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13781f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
13791f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1380984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        private boolean containsTrack(List<TvTrackInfo> tracks, String trackId) {
1381984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            for (TvTrackInfo track : tracks) {
1382984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                if (track.getId().equals(trackId)) {
1383984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                    return true;
1384984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                }
1385984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            }
1386984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            return false;
1387984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        }
1388984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee
13891f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
139010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the list of tracks for a given type. Returns {@code null} if the information is
139110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available.
13921f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
139310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
139410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
139510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @return the list of tracks for the given type.
13961f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
139710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public List<TvTrackInfo> getTracks(int type) {
13986320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
13996320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
14006320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mAudioTracks == null) {
14016320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14026320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mAudioTracks);
14046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
14056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mVideoTracks == null) {
14066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mVideoTracks);
14096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
14106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mSubtitleTracks == null) {
14116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mSubtitleTracks);
141410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
14151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
141610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
14171f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
14181f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1419d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
142010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the selected track for a given type. Returns {@code null} if the information is
142110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available or any of the tracks for the given type is not selected.
142210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *
142310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @return the ID of the selected track.
142410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @see #selectTrack
1425d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
142610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public String getSelectedTrack(int type) {
14276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
14296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedAudioTrackId;
14306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
14316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedVideoTrackId;
14326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
14336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedSubtitleTrackId;
14346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
1435d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
143610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
14371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
14381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
14391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
14406320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTracksChanged() and updates the internal track information. Returns true if
14416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * there is an update.
14426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
14436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTracks(List<TvTrackInfo> tracks) {
14446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
14466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
14476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
14486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                for (TvTrackInfo track : tracks) {
14496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (track.getType() == TvTrackInfo.TYPE_AUDIO) {
14506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mAudioTracks.add(track);
14516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_VIDEO) {
14526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mVideoTracks.add(track);
14536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) {
14546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mSubtitleTracks.add(track);
14556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14566320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
14576320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return !mAudioTracks.isEmpty() || !mVideoTracks.isEmpty()
14586320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        || !mSubtitleTracks.isEmpty();
14596320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
14606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
14616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
14626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
14636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTrackSelected() and updates the internal track selection information.
14646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns true if there is an update.
14656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
14666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTrackSelection(int type, String trackId) {
14676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO && trackId != mSelectedAudioTrackId) {
14696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedAudioTrackId = trackId;
14706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO && trackId != mSelectedVideoTrackId) {
14726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedVideoTrackId = trackId;
14736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE
14756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        && trackId != mSelectedSubtitleTrackId) {
14766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedSubtitleTrackId = trackId;
14776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
14796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
14806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return false;
14816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
14826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
14836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
14846320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns the new/updated video track that contains new video size information. Returns
14856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * null if there is no video track to notify. Subsequent calls of this method results in a
14866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * non-null video track returned only by the first call and null returned by following
14876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * calls. The caller should immediately notify of the video size change upon receiving the
14886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * track.
14896320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
14906320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        TvTrackInfo getVideoTrackToNotify() {
14916320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14926320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (!mVideoTracks.isEmpty() && mSelectedVideoTrackId != null) {
14936320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    for (TvTrackInfo track : mVideoTracks) {
14946320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        if (track.getId().equals(mSelectedVideoTrackId)) {
14956320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoWidth = track.getVideoWidth();
14966320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoHeight = track.getVideoHeight();
14976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            if (mVideoWidth != videoWidth || mVideoHeight != videoHeight) {
14986320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoWidth = videoWidth;
14996320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoHeight = videoHeight;
15006320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                return track;
15016320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            }
15026320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        }
15036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
15046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
15056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
15066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return null;
15076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
15086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
15096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
15101f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
1511a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * TvInputService.Session.appPrivateCommand()} on the current TvView.
1512a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *
1513a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param action Name of the command to be performed. This <em>must</em> be a scoped name,
1514a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            i.e. prefixed with a package name you own, so that different developers will
1515a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            not create conflicting commands.
1516a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param data Any data to include with the command.
1517a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @hide
1518a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         */
1519a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @SystemApi
1520a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(String action, Bundle data) {
1521a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            if (mToken == null) {
1522a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Log.w(TAG, "The session has been already released");
1523a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                return;
1524a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1525a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1526a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                mService.sendAppPrivateCommand(mToken, action, data, mUserId);
1527a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } catch (RemoteException e) {
1528a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                throw new RuntimeException(e);
1529a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1530a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1531a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1532a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        /**
15339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView}
15349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * should be called whenever the layout of its containing view is changed.
15359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * {@link #removeOverlayView()} should be called to remove the overlay view.
15369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Since a session can have only one overlay view, this method should be called only once
15379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * or it can be called again after calling {@link #removeOverlayView()}.
15389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
15399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param view A view playing TV.
15409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A position of the overlay view.
15419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @throws IllegalArgumentException if any of the arguments is {@code null}.
1542dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim         * @throws IllegalStateException if {@code view} is not attached to a window.
15439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
15449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void createOverlayView(View view, Rect frame) {
15459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (view == null) {
15469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("view cannot be null");
15479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (frame == null) {
15499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("frame cannot be null");
15509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (view.getWindowToken() == null) {
15529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalStateException("view must be attached to a window");
15539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1555dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1556dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
15579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
15599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
15609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
15619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
15629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
15649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
15659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
15669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Relayouts the current overlay view.
15679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
15689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A new position of the overlay view.
15699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @throws IllegalArgumentException if the arguments is {@code null}.
15709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
15719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void relayoutOverlayView(Rect frame) {
15729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (frame == null) {
15739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("frame cannot be null");
15749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1576dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1577dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
15789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
15809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.relayoutOverlayView(mToken, frame, mUserId);
15819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
15829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
15839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
15859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
15869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
15879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Removes the current overlay view.
15889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
15899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void removeOverlayView() {
15909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1591dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1592dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
15939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
15959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.removeOverlayView(mToken, mUserId);
15969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
15979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
15989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
16006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
16029bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim         * Requests to unblock content blocked by parental controls.
1603903d6b72cd572665309633e925485464d08bb25aJaewan Kim         */
16049bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        void requestUnblockContent(TvContentRating unblockedRating) {
1605903d6b72cd572665309633e925485464d08bb25aJaewan Kim            if (mToken == null) {
1606903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Log.w(TAG, "The session has been already released");
1607903d6b72cd572665309633e925485464d08bb25aJaewan Kim                return;
1608903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1609a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim            if (unblockedRating == null) {
1610a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim                throw new IllegalArgumentException("unblockedRating cannot be null");
1611a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim            }
1612903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
16139bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                mService.requestUnblockContent(mToken, unblockedRating.flattenToString(), mUserId);
1614903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } catch (RemoteException e) {
1615903d6b72cd572665309633e925485464d08bb25aJaewan Kim                throw new RuntimeException(e);
1616903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1617903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1618903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1619903d6b72cd572665309633e925485464d08bb25aJaewan Kim        /**
16206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Dispatches an input event to this session.
16216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
16228e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param event An {@link InputEvent} to dispatch.
16236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param token A token used to identify the input event later in the callback.
16246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param callback A callback used to receive the dispatch result.
16258e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param handler A {@link Handler} that the dispatch result will be delivered to.
16266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns
16276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns
16286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will
16296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         be invoked later.
16306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @throws IllegalArgumentException if any of the necessary arguments is {@code null}.
16316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
16326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
16336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public int dispatchInputEvent(InputEvent event, Object token,
16346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                FinishedInputEventCallback callback, Handler handler) {
16356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (event == null) {
16366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                throw new IllegalArgumentException("event cannot be null");
16376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (callback != null && handler == null) {
16396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                throw new IllegalArgumentException("handler cannot be null");
16406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
16426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mChannel == null) {
16436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_NOT_HANDLED;
16446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                PendingEvent p = obtainPendingEventLocked(event, token, callback, handler);
16466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (Looper.myLooper() == Looper.getMainLooper()) {
16476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    // Already running on the main thread so we can send the event immediately.
16486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return sendInputEventOnMainLooperLocked(p);
16496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the main thread.
16526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p);
16536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
16546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandler.sendMessage(msg);
16556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return DISPATCH_IN_PROGRESS;
16566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
16586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
16606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Callback that is invoked when an input event that was dispatched to this session has been
16616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * finished.
16626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
16636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
16646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
16656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public interface FinishedInputEventCallback {
16666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            /**
16676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * Called when the dispatched input event is finished.
16686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *
16698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim             * @param token A token passed to {@link #dispatchInputEvent}.
16706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * @param handled {@code true} if the dispatched input event was handled properly.
16716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *            {@code false} otherwise.
16726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             */
16736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void onFinishedInputEvent(Object token, boolean handled);
16746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
16756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Must be called on the main looper
16776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
16786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
16796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int result = sendInputEventOnMainLooperLocked(p);
16806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (result == DISPATCH_IN_PROGRESS) {
16816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return;
16826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, false);
16866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
16876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private int sendInputEventOnMainLooperLocked(PendingEvent p) {
16896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (mChannel != null) {
16906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender == null) {
16916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mSender = new TvInputEventSender(mChannel, mHandler.getLooper());
16926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final InputEvent event = p.mEvent;
16956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final int seq = event.getSequenceNumber();
16966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender.sendInputEvent(seq, event)) {
16976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mPendingEvents.put(seq, p);
16986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
16996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    msg.setAsynchronous(true);
17006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT);
17016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_IN_PROGRESS;
17026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:"
17056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        + event);
17066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return DISPATCH_NOT_HANDLED;
17086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void finishedInputEvent(int seq, boolean handled, boolean timeout) {
17116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final PendingEvent p;
17126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
17136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int index = mPendingEvents.indexOfKey(seq);
17146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (index < 0) {
17156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return; // spurious, event already finished or timed out
17166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = mPendingEvents.valueAt(index);
17196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mPendingEvents.removeAt(index);
17206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (timeout) {
17226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Log.w(TAG, "Timeout waiting for seesion to handle input event after "
17236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                            + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken);
17246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                } else {
17256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
17266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, handled);
17306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Assumes the event has already been removed from the queue.
17336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
17346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mHandled = handled;
17355b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            if (p.mEventHandler.getLooper().isCurrentThread()) {
17366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Already running on the callback handler thread so we can send the callback
17376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // immediately.
17386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p.run();
17396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            } else {
17406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the callback handler thread.
17416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // In this case, the callback will be responsible for recycling the event.
17425b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                Message msg = Message.obtain(p.mEventHandler, p);
17436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
17446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
17456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void flushPendingEventsLocked() {
17496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
17506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final int count = mPendingEvents.size();
17526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            for (int i = 0; i < count; i++) {
17536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int seq = mPendingEvents.keyAt(i);
17546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0);
17556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
17566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
17576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
17616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                FinishedInputEventCallback callback, Handler handler) {
17626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            PendingEvent p = mPendingEventPool.acquire();
17636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (p == null) {
17646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = new PendingEvent();
17656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mEvent = event;
17675b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventToken = token;
17686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mCallback = callback;
17695b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventHandler = handler;
17706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return p;
17716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void recyclePendingEventLocked(PendingEvent p) {
17746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.recycle();
17756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mPendingEventPool.release(p);
17766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
1778bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        IBinder getToken() {
1779bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            return mToken;
1780bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        }
1781bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang
17822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private void releaseInternal() {
17832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mToken = null;
17842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mHandler) {
17852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mChannel != null) {
17862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (mSender != null) {
17872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        flushPendingEventsLocked();
17882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender.dispose();
17892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender = null;
17902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
17912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel.dispose();
17922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel = null;
17932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
17942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
17952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mSessionCallbackRecordMap) {
17962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSessionCallbackRecordMap.remove(mSeq);
17972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
17982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
17992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
18006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class InputEventHandler extends Handler {
18016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_SEND_INPUT_EVENT = 1;
18026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
18036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_FLUSH_INPUT_EVENT = 3;
18046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            InputEventHandler(Looper looper) {
18066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(looper, null, true);
18076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void handleMessage(Message msg) {
18116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                switch (msg.what) {
18126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_SEND_INPUT_EVENT: {
18136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj);
18146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_TIMEOUT_INPUT_EVENT: {
18176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, true);
18186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_FLUSH_INPUT_EVENT: {
18216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, false);
18226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
18256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class TvInputEventSender extends InputEventSender {
18296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public TvInputEventSender(InputChannel inputChannel, Looper looper) {
18306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(inputChannel, looper);
18316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void onInputEventFinished(int seq, boolean handled) {
18356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                finishedInputEvent(seq, handled, false);
18366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class PendingEvent implements Runnable {
18406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public InputEvent mEvent;
18415b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Object mEventToken;
18426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public FinishedInputEventCallback mCallback;
18435b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Handler mEventHandler;
18446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public boolean mHandled;
18456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void recycle() {
18476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mEvent = null;
18485b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventToken = null;
18496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mCallback = null;
18505b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventHandler = null;
18516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandled = false;
18526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void run() {
18565b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mCallback.onFinishedInputEvent(mEventToken, mHandled);
18576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18585b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                synchronized (mEventHandler) {
18596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    recyclePendingEventLocked(this);
18606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
18616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1864d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1865d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1866d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * The Hardware provides the per-hardware functionality of TV hardware.
1867d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1868d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * TV hardware is physical hardware attached to the Android device; for example, HDMI ports,
1869d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Component/Composite ports, etc. Specifically, logical devices such as HDMI CEC logical
1870d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * devices don't fall into this category.
1871d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1872d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1873d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1874d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1875d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public final static class Hardware {
1876d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private final ITvInputHardware mInterface;
1877d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1878d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private Hardware(ITvInputHardware hardwareInterface) {
1879d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mInterface = hardwareInterface;
1880d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1881d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1882d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private ITvInputHardware getInterface() {
1883d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mInterface;
1884d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1885d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1886d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean setSurface(Surface surface, TvStreamConfig config) {
1887d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1888d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.setSurface(surface, config);
1889d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1890d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1891d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1892d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1893d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1894d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void setStreamVolume(float volume) {
1895d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1896d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.setStreamVolume(volume);
1897d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1898d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1899d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1900d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1901d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1902d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean dispatchKeyEventToHdmi(KeyEvent event) {
1903d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1904d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.dispatchKeyEventToHdmi(event);
1905d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1906d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1907d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1908d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1909d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1910d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
1911d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                int channelMask, int format) {
1912d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1913d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.overrideAudioSink(audioType, audioAddress, samplingRate, channelMask,
1914d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                        format);
1915d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1916d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1917d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1918d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1919d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
19203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
1921