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    /**
75993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * The TV input is in unknown state.
76993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * <p>
77993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * State for denoting unknown TV input state. The typical use case is when a requested TV
78993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * input is removed from the device or it is not registered. Used in
79993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * {@code ITvInputManager.getTvInputState()}.
80993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * </p>
81993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     * @hide
82993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang     */
83993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang    public static final int INPUT_STATE_UNKNOWN = -1;
84993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang
85993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang    /**
86969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is connected.
87969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
88969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
892778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
90969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
91969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
92969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED = 0;
93969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
94969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is connected but in standby mode. It would take a while until it becomes
95969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * fully ready.
96969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
97969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
982778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
99969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
100969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
101969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED_STANDBY = 1;
102969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
103969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * The TV input is disconnected.
104969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <p>
105969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * State for {@link #getInputState} and {@link
1062778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * TvInputManager.TvInputCallback#onInputStateChanged}.
107969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </p>
108969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
109969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_DISCONNECTED = 2;
110969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
111783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
112783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the user blocked content ratings change. For use with the
113783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isRatingBlocked}.
114783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
115783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_BLOCKED_RATINGS_CHANGED =
1162778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
117783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
118783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
119783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the parental controls enabled state changes. For use with the
120783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isParentalControlsEnabled}.
121783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
122783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED =
1232778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
1249c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
1259c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
1269c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Broadcast intent action used to query available content rating systems.
1279c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p>
1289c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * The TV input manager service locates available content rating systems by querying broadcast
1299c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * receivers that are registered for this action. An application can offer additional content
1309c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * rating systems to the user by declaring a suitable broadcast receiver in its manifest.
1319c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p><p>
1329c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Here is an example broadcast receiver declaration that an application might include in its
1339c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * AndroidManifest.xml to advertise custom content rating systems. The meta-data specifies a
1349c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * resource that contains a description of each content rating system that is provided by the
1359c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * application.
1369c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p><pre class="prettyprint">
1379c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * {@literal
1389c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <receiver android:name=".TvInputReceiver">
1399c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <intent-filter>
1409c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *         <action android:name=
1414e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *                 "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
1429c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     </intent-filter>
1439c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <meta-data
1444e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *             android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
1459c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *             android:resource="@xml/tv_content_rating_systems" />
1469c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </receiver>}</pre></p>
1479c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * In the above example, the <code>@xml/tv_content_rating_systems</code> resource refers to an
1489c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * XML resource whose root element is <code>&lt;rating-system-definitions&gt;</code> that
1499c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * contains zero or more <code>&lt;rating-system-definition&gt;</code> elements. Each <code>
1509c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * &lt;rating-system-definition&gt;</code> element specifies the ratings, sub-ratings and rating
1519c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * orders of a particular content rating system.
1529c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p>
1539c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *
1549c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * @see TvContentRating
1559c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
1569c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String ACTION_QUERY_CONTENT_RATING_SYSTEMS =
1572778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
1589c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
1599c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
1609c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Content rating systems metadata associated with {@link #ACTION_QUERY_CONTENT_RATING_SYSTEMS}.
1619c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p>
1629c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Specifies the resource ID of an XML resource that describes the content rating systems that
1639c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * are provided by the application.
1649c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * </p>
1659c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
1669c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String META_DATA_CONTENT_RATING_SYSTEMS =
1672778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
168783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputManager mService;
1703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
171969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private final Object mLock = new Object();
172969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
1742778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private final List<TvInputCallbackRecord> mCallbackRecords =
1752778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            new LinkedList<TvInputCallbackRecord>();
176969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
177969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    // A mapping from TV input ID to the state of corresponding input.
1786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
179969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private final Map<String, Integer> mStateMap = new ArrayMap<String, Integer>();
1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // A mapping from the sequence number of a session to its SessionCallbackRecord.
1822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
1832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            new SparseArray<SessionCallbackRecord>();
1843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A sequence number for the next session to be created. Should be protected by a lock
1862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // {@code mSessionCallbackRecordMap}.
1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mNextSeq;
1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputClient mClient;
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1912778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private final ITvInputManagerCallback mManagerCallback;
192969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final int mUserId;
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Interface used to receive the created session.
197b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
19915bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
2002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    public abstract static class SessionCallback {
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * This is called after {@link TvInputManager#createSession} has been processed.
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param session A {@link TvInputManager.Session} instance created. This can be
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *            {@code null} if the creation request failed.
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
2072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionCreated(Session session) {
2082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
2092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
2102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        /**
2112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This is called when {@link TvInputManager.Session} is released.
2122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This typically happens when the process hosting the session has crashed or been killed.
2132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         *
2142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * @param session A {@link TvInputManager.Session} instance released.
2152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         */
2162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionReleased(Session session) {
2172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
218832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
219832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
2201f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the channel of this session is changed by the underlying TV input
2216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * without any {@link TvInputManager.Session#tune(Uri)} request.
222a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         *
223d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param channelUri The URI of a channel.
225a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         */
2261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(Session session, Uri channelUri) {
227832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
228832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
229832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
2301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the track information of the session has been changed.
231b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         *
232d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param tracks A list which includes track information.
234b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         */
23510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(Session session, List<TvTrackInfo> tracks) {
236b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
237b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
238b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        /**
23910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * This is called when a track for a given type is selected.
2409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
2416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
24210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the selected track. The type can be
24310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
24410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
24510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the selected track. When {@code null} the currently selected
24610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track for a given type should be unselected.
247d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
24810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTrackSelected(Session session, int type, String trackId) {
249d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
250d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
251d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
2526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * This is invoked when the video size has been changed. It is also called when the first
2536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * time video size information becomes available after the session is tuned to a specific
2546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * channel.
2556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         *
2566320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2576320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param width The width of the video.
2586320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param height The height of the video.
2596320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
2606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(Session session, int width, int height) {
2616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
2626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
2636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
264d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * This is called when the video is available, so the TV input starts the playback.
265d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         *
266d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
2679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
2689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoAvailable(Session session) {
2699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
2709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
2719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
2729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is not available, so the TV input stops the playback.
2739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
2749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback
2759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param reason The reason why the TV input stopped the playback:
2769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <ul>
2779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
2786e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
2799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
2809b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
2819b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * </ul>
2829b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
2839b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoUnavailable(Session session, int reason) {
2849b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
2859b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
2869b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
287bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be allowed to watch since
288bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * its content rating is not blocked by parental controls.
289bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         *
290bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback
291bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         */
292bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(Session session) {
293bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
294bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
295bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        /**
296bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be not allowed to watch
297bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * since its content rating is blocked by parental controls.
2986057102dbb746593a7d59cf377c969b62e38c664Jae Seo         *
2996057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback
3006057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param rating The content ration of the blocked program.
3016057102dbb746593a7d59cf377c969b62e38c664Jae Seo         */
3026057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(Session session, TvContentRating rating) {
3036057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
3046057102dbb746593a7d59cf377c969b62e38c664Jae Seo
3056057102dbb746593a7d59cf377c969b62e38c664Jae Seo        /**
3065b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * This is called when {@link TvInputService.Session#layoutSurface} is called to change the
3075b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * layout of surface.
308ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         *
309ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         * @param session A {@link TvInputManager.Session} associated with this callback
3105b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param left Left position.
3115b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param top Top position.
3125b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param right Right position.
3135b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param bottom Bottom position.
314ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         * @hide
315ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         */
316ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        @SystemApi
317ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
318ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
319ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
320ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        /**
321832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * This is called when a custom event has been sent from this session.
322832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         *
323832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param session A {@link TvInputManager.Session} associated with this callback
324832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventType The type of the event.
325832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventArgs Optional arguments of the event.
326832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @hide
327832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         */
32815bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
329832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
330832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private static final class SessionCallbackRecord {
3342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SessionCallback mSessionCallback;
3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
3362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session mSession;
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3386320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        SessionCallbackRecord(SessionCallback sessionCallback,
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Handler handler) {
3402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallback = sessionCallback;
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionCreated(final Session session) {
3452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSession = session;
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
3492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionCreated(session);
3502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
3512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            });
3522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
3532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionReleased() {
3552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mHandler.post(new Runnable() {
3562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                @Override
3572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                public void run() {
3582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionReleased(mSession);
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
362832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
3636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postChannelRetuned(final Uri channelUri) {
364832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
365832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
366832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
3671f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    mSessionCallback.onChannelRetuned(mSession, channelUri);
368832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
369832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
370832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
371832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
3726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTracksChanged(final List<TvTrackInfo> tracks) {
373b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            mHandler.post(new Runnable() {
374b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                @Override
375b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                public void run() {
37610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTracksChanged(mSession, tracks);
377b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
378b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            });
379b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
380b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
3816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTrackSelected(final int type, final String trackId) {
382d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            mHandler.post(new Runnable() {
383d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                @Override
384d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                public void run() {
38510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTrackSelected(mSession, type, trackId);
386d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
387d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            });
388d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
389d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
3906320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoSizeChanged(final int width, final int height) {
3916320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            mHandler.post(new Runnable() {
3926320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                @Override
3936320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                public void run() {
3946320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSessionCallback.onVideoSizeChanged(mSession, width, height);
3956320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
3966320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            });
3976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
3986320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
3996320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoAvailable() {
4009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
4019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
4029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
4039b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoAvailable(mSession);
4049b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
4059b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
4069b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
4079b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
4086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoUnavailable(final int reason) {
4099b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
4109b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
4119b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
4129b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoUnavailable(mSession, reason);
4139b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
4149b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
4159b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
4169b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
4176320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentAllowed() {
418bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            mHandler.post(new Runnable() {
419bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                @Override
420bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                public void run() {
421bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    mSessionCallback.onContentAllowed(mSession);
422bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
423bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            });
424bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
425bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
4266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentBlocked(final TvContentRating rating) {
4276057102dbb746593a7d59cf377c969b62e38c664Jae Seo            mHandler.post(new Runnable() {
4286057102dbb746593a7d59cf377c969b62e38c664Jae Seo                @Override
4296057102dbb746593a7d59cf377c969b62e38c664Jae Seo                public void run() {
4306057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    mSessionCallback.onContentBlocked(mSession, rating);
4316057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
4326057102dbb746593a7d59cf377c969b62e38c664Jae Seo            });
4336057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
4346057102dbb746593a7d59cf377c969b62e38c664Jae Seo
4356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postLayoutSurface(final int left, final int top, final int right,
436ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                final int bottom) {
437ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mHandler.post(new Runnable() {
438ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                @Override
439ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                public void run() {
440ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    mSessionCallback.onLayoutSurface(mSession, left, top, right, bottom);
441ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
442ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            });
443ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
444ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
4456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionEvent(final String eventType, final Bundle eventArgs) {
446832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
447832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
448832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
449832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    mSessionCallback.onSessionEvent(mSession, eventType, eventArgs);
450832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
451832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
452832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
4562778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Callback used to monitor status of the TV input.
4573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
4582778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public abstract static class TvInputCallback {
4593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
460969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * This is called when the state of a given TV input is changed.
4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
4628e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4638e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param state State of the TV input. The value is one of the following:
464969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <ul>
465969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED}
466969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY}
467969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_DISCONNECTED}
468969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * </ul>
4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
470969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void onInputStateChanged(String inputId, int state) {
4713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
4738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
4748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * This is called when a TV input is added.
4758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
4768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
4788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputAdded(String inputId) {
4798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
4808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
4818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
4828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * This is called when a TV input is removed.
4838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
4848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param inputId The id of the TV input.
4858e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
4868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputRemoved(String inputId) {
4878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
48819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
48919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        /**
49019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * This is called when a TV input is updated. The update of TV input happens when it is
49119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * reinstalled or the media on which the newer version of TV input exists is
49219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * available/unavailable.
49319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         *
49419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * @param inputId The id of the TV input.
49519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         * @hide
49619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         */
49719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        @SystemApi
49819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        public void onInputUpdated(String inputId) {
49919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5022778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private static final class TvInputCallbackRecord {
5032778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        private final TvInputCallback mCallback;
5043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
5053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5062778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallbackRecord(TvInputCallback callback, Handler handler) {
5072778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallback = callback;
5083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
5093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5112778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallback getCallback() {
5122778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            return mCallback;
5138e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
5148e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
5158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputStateChanged(final String inputId, final int state) {
5168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
5178e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
5188e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
5192778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputStateChanged(inputId, state);
5208e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
5218e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
5228e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
5238e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
5248e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputAdded(final String inputId) {
5258e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
5268e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
5278e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
5282778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputAdded(inputId);
5298e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
5308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5338e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void postInputRemoved(final String inputId) {
5343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
5363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
5372778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    mCallback.onInputRemoved(inputId);
5383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
5403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
54119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
54219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        public void postInputUpdated(final String inputId) {
54319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            mHandler.post(new Runnable() {
54419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                @Override
54519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                public void run() {
546db8f7ab752de641b147015a2b4a134913fbcb594Youngsang Cho                    mCallback.onInputUpdated(inputId);
54719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
54819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            });
54919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
5503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
553d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Interface used to receive events from Hardware objects.
554d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
555d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
556d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
557d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public abstract static class HardwareCallback {
558d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onReleased();
559d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
560d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
561d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
562d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @hide
5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManager(ITvInputManager service, int userId) {
5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mService = service;
5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mUserId = userId;
5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mClient = new ITvInputClient.Stub() {
5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
570d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
5716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    int seq) {
5722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
5732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (record == null) {
5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "Callback not found for " + token);
5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Session session = null;
5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (token != null) {
5802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        session = new Session(token, channel, mService, mUserId, seq,
5812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                                mSessionCallbackRecordMap);
5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    record.postSessionCreated(session);
5843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
5882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            public void onSessionReleased(int seq) {
5892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
5902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
5912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallbackRecordMap.delete(seq);
5922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (record == null) {
5932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Log.e(TAG, "Callback not found for seq:" + seq);
5942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
5952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
5962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.mSession.releaseInternal();
5972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.postSessionReleased();
5982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
5992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
6002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
6012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            @Override
6021f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri, int seq) {
603a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mSessionCallbackRecordMap) {
604a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
605a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (record == null) {
606a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
607a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
608a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
6091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    record.postChannelRetuned(channelUri);
610a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
611a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
612a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
613a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
61410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks, int seq) {
615832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
616832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
617832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
618832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
619832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
620832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
6216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTracks(tracks)) {
6226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTracksChanged(tracks);
6236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
6246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
625b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
626b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
627b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
628b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
62910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId, int seq) {
630d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mSessionCallbackRecordMap) {
631d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
632d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (record == null) {
633d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
634d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
635d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
6366320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTrackSelection(type, trackId)) {
6376320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTrackSelected(type, trackId);
6386320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
6396320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
6406320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
6416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
6426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
6436320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            private void postVideoSizeChangedIfNeededLocked(SessionCallbackRecord record) {
6446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                TvTrackInfo track = record.mSession.getVideoTrackToNotify();
6456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (track != null) {
6466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    record.postVideoSizeChanged(track.getVideoWidth(), track.getVideoHeight());
647d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
648d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
649d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
650d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
6519b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable(int seq) {
6529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
6539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
6559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
6569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoAvailable();
6599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
6639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason, int seq) {
6649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
6659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
6679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
6689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoUnavailable(reason);
6719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
675bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed(int seq) {
676bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mSessionCallbackRecordMap) {
677bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
678bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (record == null) {
679bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
680bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
681bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
682bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    record.postContentAllowed();
683bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
684bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
685bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
686bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6876057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating, int seq) {
6886057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mSessionCallbackRecordMap) {
6896057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
6906057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (record == null) {
6916057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
6926057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6936057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6946057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    record.postContentBlocked(TvContentRating.unflattenFromString(rating));
6956057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6966057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6976057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6986057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
699ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom, int seq) {
700ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mSessionCallbackRecordMap) {
701ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
702ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (record == null) {
703ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
704ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
705ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
706ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    record.postLayoutSurface(left, top, right, bottom);
707ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
708ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
709ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
710ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
711832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs, int seq) {
712832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
713832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
714832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
715832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
716832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
717832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
718832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    record.postSessionEvent(eventType, eventArgs);
719832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
720832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
721969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        };
7222778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        mManagerCallback = new ITvInputManagerCallback.Stub() {
723832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
724969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            public void onInputStateChanged(String inputId, int state) {
725969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                synchronized (mLock) {
726969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    mStateMap.put(inputId, state);
7272778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7288e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputStateChanged(inputId, state);
7298e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
7308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
7318e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7328e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7338e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
7348e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputAdded(String inputId) {
7358e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
7368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.put(inputId, INPUT_STATE_CONNECTED);
7372778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7388e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputAdded(inputId);
7398e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
7408e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
7418e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7428e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7438e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
7448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputRemoved(String inputId) {
7458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
7468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.remove(inputId);
7472778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
7488e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputRemoved(inputId);
7493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
7503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
7513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
75219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
75319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
75419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onInputUpdated(String inputId) {
75519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                synchronized (mLock) {
756db8f7ab752de641b147015a2b4a134913fbcb594Youngsang Cho                    for (TvInputCallbackRecord record : mCallbackRecords) {
75719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                        record.postInputUpdated(inputId);
75819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    }
75919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
76019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
7613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
762969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        try {
7639127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            if (mService != null) {
7649127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo                mService.registerCallback(mManagerCallback, mUserId);
765993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                List<TvInputInfo> infos = mService.getTvInputList(mUserId);
766993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                synchronized (mLock) {
767993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                    for (TvInputInfo info : infos) {
768993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                        String inputId = info.getId();
769993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                        int state = mService.getTvInputState(inputId, mUserId);
770993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                        if (state != INPUT_STATE_UNKNOWN) {
771993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                            mStateMap.put(inputId, state);
772993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                        }
773993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                    }
774993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                }
7759127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            }
776969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } catch (RemoteException e) {
777993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang            Log.e(TAG, "TvInputManager initialization failed: " + e);
778969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
7793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
7823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Returns the complete list of TV inputs on the system.
7833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
7843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @return List of {@link TvInputInfo} for each TV input that describes its meta information.
7853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
7863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public List<TvInputInfo> getTvInputList() {
7873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
7883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return mService.getTvInputList(mUserId);
7893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
7903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new RuntimeException(e);
7913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
795b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * Returns the {@link TvInputInfo} for a given TV input.
796b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     *
797b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @param inputId The ID of the TV input.
798b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @return the {@link TvInputInfo} for a given TV input. {@code null} if not found.
799b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     */
800b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    public TvInputInfo getTvInputInfo(String inputId) {
801783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (inputId == null) {
802783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("inputId cannot be null");
803783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
804b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        try {
805b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            return mService.getTvInputInfo(inputId, mUserId);
806b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        } catch (RemoteException e) {
807b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            throw new RuntimeException(e);
808b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
809b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    }
810b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
811b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    /**
8126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo     * Returns the state of a given TV input. It returns one of the following:
813969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <ul>
814969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED}
815969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED_STANDBY}
816969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_DISCONNECTED}
817969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </ul>
8183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
8198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param inputId The id of the TV input.
820969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * @throws IllegalArgumentException if the argument is {@code null} or if there is no
821969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     *        {@link TvInputInfo} corresponding to {@code inputId}.
8223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
823969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public int getInputState(String inputId) {
824d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (inputId == null) {
825783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("inputId cannot be null");
8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
827969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
828969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            Integer state = mStateMap.get(inputId);
829969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (state == null) {
830969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throw new IllegalArgumentException("Unrecognized input ID: " + inputId);
8313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
832969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return state.intValue();
8333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
8372778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Registers a {@link TvInputCallback}.
8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
8392778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback A callback used to monitor status of the TV inputs.
8408e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the status change will be delivered to.
8413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
8432778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public void registerCallback(TvInputCallback callback, Handler handler) {
8442778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        if (callback == null) {
8458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            throw new IllegalArgumentException("callback cannot be null");
8463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (handler == null) {
8483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("handler cannot be null");
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
850969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
8512778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallbackRecords.add(new TvInputCallbackRecord(callback, handler));
8523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
8562778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Unregisters the existing {@link TvInputCallback}.
8573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
8582778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback The existing callback to remove.
8593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
8603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
8612778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public void unregisterCallback(final TvInputCallback callback) {
8622778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        if (callback == null) {
8638e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            throw new IllegalArgumentException("callback cannot be null");
8643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
865969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
8662778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            for (Iterator<TvInputCallbackRecord> it = mCallbackRecords.iterator();
867969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    it.hasNext(); ) {
8682778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                TvInputCallbackRecord record = it.next();
8692778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                if (record.getCallback() == callback) {
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    it.remove();
871969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    break;
8723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
878783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the user's parental controls enabled state.
879783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
880783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the user enabled the parental controls, {@code false} otherwise.
881783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
882783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public boolean isParentalControlsEnabled() {
883783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
884783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isParentalControlsEnabled(mUserId);
885783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
886783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
887783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
888783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
889783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
890783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
891783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Sets the user's parental controls enabled state.
892783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
893783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param enabled The user's parental controls enabled state. {@code true} if the user enabled
894783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *            the parental controls, {@code false} otherwise.
895783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isParentalControlsEnabled
896783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
897783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
898783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
899783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void setParentalControlsEnabled(boolean enabled) {
900783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
901783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.setParentalControlsEnabled(enabled, mUserId);
902783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
903783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
904783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
905783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
906783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
907783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
908783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Checks whether a given TV content rating is blocked by the user.
909783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
910783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The TV content rating to check.
911783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the given TV content rating is blocked, {@code false} otherwise.
912783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
913783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public boolean isRatingBlocked(TvContentRating rating) {
914783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
915783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
916783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
917783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
918783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isRatingBlocked(rating.flattenToString(), mUserId);
919783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
920783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
921783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
922783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
923783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
924783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
925783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the list of blocked content ratings.
926783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
927783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return the list of content ratings blocked by the user.
928783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
929783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
930783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
931783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public List<TvContentRating> getBlockedRatings() {
932783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
933783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            List<TvContentRating> ratings = new ArrayList<TvContentRating>();
934783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            for (String rating : mService.getBlockedRatings(mUserId)) {
935783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                ratings.add(TvContentRating.unflattenFromString(rating));
936783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
937783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return ratings;
938783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
939783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
940783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
941783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
942783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Adds a user blocked content rating.
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
946783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to block.
947783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
948783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #removeBlockedRating
949783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
950783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
951783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void addBlockedRating(TvContentRating rating) {
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
955783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
956783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
957783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.addBlockedRating(rating.flattenToString(), mUserId);
958783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
959783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
960783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
961783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
962783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
963783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
964783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Removes a user blocked content rating.
965783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
966783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to unblock.
967783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
968783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #addBlockedRating
969783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
970783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
971783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
972783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void removeBlockedRating(TvContentRating rating) {
973783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        if (rating == null) {
974783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new IllegalArgumentException("rating cannot be null");
975783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
976783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
977783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.removeBlockedRating(rating.flattenToString(), mUserId);
978783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
979783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            throw new RuntimeException(e);
980783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
981783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
982783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
983783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
9849c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Returns the list of all TV content rating systems defined.
9855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     * @hide
9865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     */
9875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    @SystemApi
9889c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
9895c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        try {
9909c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            return mService.getTvContentRatingSystemList(mUserId);
9915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        } catch (RemoteException e) {
9925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            throw new RuntimeException(e);
9935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
9945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    }
9955c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
9965c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    /**
997674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho     * Creates a {@link Session} for a given TV input.
9983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * <p>
9993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * The number of sessions that can be created at the same time is limited by the capability of
10003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * the given TV input.
10013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * </p>
10023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
10038e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param inputId The id of the TV input.
10048e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param callback A callback used to receive the created session.
10058e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the session creation will be delivered to.
10063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @throws IllegalArgumentException if any of the arguments is {@code null}.
1007b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
10083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
100915bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
10102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    public void createSession(String inputId, final SessionCallback callback,
10113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Handler handler) {
1012d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (inputId == null) {
1013d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            throw new IllegalArgumentException("id cannot be null");
10143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (callback == null) {
10163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("callback cannot be null");
10173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (handler == null) {
10193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("handler cannot be null");
10203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionCallbackRecord record = new SessionCallbackRecord(callback, handler);
10222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        synchronized (mSessionCallbackRecordMap) {
10233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            int seq = mNextSeq++;
10242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap.put(seq, record);
10253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
1026d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mService.createSession(mClient, inputId, seq, mUserId);
10273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
10283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
10293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
10323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1033b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
1034c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Returns the TvStreamConfig list of the given TV input.
1035c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
103690e733385d466acd87730676c83c080a17ff495fWonsik Kim     * If you are using {@link Hardware} object from {@link
103790e733385d466acd87730676c83c080a17ff495fWonsik Kim     * #acquireTvInputHardware}, you should get the list of available streams
103890e733385d466acd87730676c83c080a17ff495fWonsik Kim     * from {@link HardwareCallback#onStreamConfigChanged} method, not from
103990e733385d466acd87730676c83c080a17ff495fWonsik Kim     * here. This method is designed to be used with {@link #captureFrame} in
104090e733385d466acd87730676c83c080a17ff495fWonsik Kim     * capture scenarios specifically and not suitable for any other use.
104190e733385d466acd87730676c83c080a17ff495fWonsik Kim     *
1042c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param inputId the id of the TV input.
1043c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return List of {@link TvStreamConfig} which is available for capturing
1044c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *   of the given TV input.
1045c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1046c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1047c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1048c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
1049c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1050c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.getAvailableTvStreamConfigList(inputId, mUserId);
1051c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1052c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            throw new RuntimeException(e);
1053c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1054c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1055c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1056c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1057c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Take a snapshot of the given TV input into the provided Surface.
1058c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
1059c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param inputId the id of the TV input.
1060c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param surface the {@link Surface} to which the snapshot is captured.
1061c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param config the {@link TvStreamConfig} which is used for capturing.
1062c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return true when the {@link Surface} is ready to be captured.
1063c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1064c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1065c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1066c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
1067c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1068c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.captureFrame(inputId, surface, config, mUserId);
1069c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1070c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            throw new RuntimeException(e);
1071df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1072df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    }
1073df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1074df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    /**
1075df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * Returns true if there is only a single TV input session.
1076df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     *
1077df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * @hide
1078df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     */
1079df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    @SystemApi
1080df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    public boolean isSingleSessionActive() {
1081df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        try {
1082df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            return mService.isSingleSessionActive(mUserId);
1083df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        } catch (RemoteException e) {
1084df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            throw new RuntimeException(e);
1085c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1086c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1087c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1088c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1089d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Returns a list of TvInputHardwareInfo objects representing available hardware.
1090d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1091d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1092d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1093d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1094d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public List<TvInputHardwareInfo> getHardwareList() {
1095d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1096d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mService.getHardwareList();
1097d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1098d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1099d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1100d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1101d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1102d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1103d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Returns acquired TvInputManager.Hardware object for given deviceId.
1104d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1105d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * If there are other Hardware object acquired for the same deviceId, calling this method will
1106d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * preempt the previously acquired object and report {@link HardwareCallback#onReleased} to the
1107d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * old object.
1108d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1109d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1110d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1111d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1112d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
1113d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            TvInputInfo info) {
1114d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1115d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return new Hardware(
1116d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
1117d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1118d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onReleased() {
1119d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onReleased();
1120d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1121d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1122d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1123d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onStreamConfigChanged(TvStreamConfig[] configs) {
1124d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onStreamConfigChanged(configs);
1125d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1126d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }, info, mUserId));
1127d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1128d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1129d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1130d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1131d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1132d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1133d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Releases previously acquired hardware object.
1134d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1135d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1136d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1137d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1138d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public void releaseTvInputHardware(int deviceId, Hardware hardware) {
1139d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1140d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
1141d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1142d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            throw new RuntimeException(e);
1143d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1144d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1145d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1146d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1147b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * The Session provides the per-session functionality of TV inputs.
1148b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
1149b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
115015bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo    @SystemApi
11513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public static final class Session {
11526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_IN_PROGRESS = -1;
11536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_NOT_HANDLED = 0;
11546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_HANDLED = 1;
11556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
11576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ITvInputManager mService;
11593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
11602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mSeq;
11616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // For scheduling input event handling on the main thread. This also serves as a lock to
11636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // protect pending input events and the input channel.
11646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper());
11656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
11676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
11682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
11696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
11709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        private IBinder mToken;
11716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private TvInputEventSender mSender;
11726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private InputChannel mChannel;
11736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
11746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private final Object mTrackLock = new Object();
11756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
117610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mAudioTracks = new ArrayList<TvTrackInfo>();
11776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
117810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mVideoTracks = new ArrayList<TvTrackInfo>();
11796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
118010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private final List<TvTrackInfo> mSubtitleTracks = new ArrayList<TvTrackInfo>();
11816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
118210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedAudioTrackId;
11836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
118410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedVideoTrackId;
11856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
118610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedSubtitleTrackId;
11876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
11886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoWidth;
11896320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        // @GuardedBy("mTrackLock")
11906320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoHeight;
11913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
11932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
11943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mToken = token;
11956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mChannel = channel;
11963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mService = service;
11973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
11982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
11992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap = sessionCallbackRecordMap;
12003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
12033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Releases this session.
12043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
12053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void release() {
12069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1207dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1208dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
12099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.releaseSession(mToken, mUserId);
12123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
12133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
12143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
12162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            releaseInternal();
12173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
122015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * Sets this as the main session. The main session is a session whose corresponding TV
122115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * input determines the HDMI-CEC active source device.
122215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         *
122315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * @see TvView#setMain
12244c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee         */
122515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        void setMain() {
12264c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            if (mToken == null) {
12274c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Log.w(TAG, "The session has been already released");
12284c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                return;
12294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
12304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
12314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                mService.setMainSession(mToken, mUserId);
12324c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } catch (RemoteException e) {
12334c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                throw new RuntimeException(e);
12344c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
12354c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
12364c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
12374c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        /**
12383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Sets the {@link android.view.Surface} for this session.
12393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
12403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param surface A {@link android.view.Surface} used to render video.
12413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1242f1c025cbcd98f2366d384c5aac114c330090a645Wonsik Kim        public void setSurface(Surface surface) {
12439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1244dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1245dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
12469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // surface can be null.
12483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setSurface(mToken, surface, mUserId);
12503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
12513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
12523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
1256e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * Notifies of any structural changes (format or size) of the {@link Surface}
1257e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * passed by {@link #setSurface}.
1258e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         *
1259e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param format The new PixelFormat of the {@link Surface}.
1260e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param width The new width of the {@link Surface}.
1261e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @param height The new height of the {@link Surface}.
1262e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         * @hide
1263e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         */
126415bbf3b220fdd22df62f2bfa04452f4cdf11d2bbJae Seo        @SystemApi
1265e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(int format, int width, int height) {
1266e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (mToken == null) {
1267e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Log.w(TAG, "The session has been already released");
1268e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1269e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1270e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1271e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
1272e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } catch (RemoteException e) {
1273e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                throw new RuntimeException(e);
1274e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1275e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1276e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1277e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        /**
1278782f7345471072b630e58c7abd3579b0015273b1Jae Seo         * Sets the relative stream volume of this session to handle a change of audio focus.
12793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
12803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param volume A volume value between 0.0f to 1.0f.
12813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @throws IllegalArgumentException if the volume value is out of range.
12823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1283782f7345471072b630e58c7abd3579b0015273b1Jae Seo        public void setStreamVolume(float volume) {
12849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1285dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1286dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
12879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (volume < 0.0f || volume > 1.0f) {
12903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    throw new IllegalArgumentException("volume should be between 0.0f and 1.0f");
12913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setVolume(mToken, volume, mUserId);
12933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
12943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
12953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
12993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Tunes to a given channel.
13003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
13013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param channelUri The URI of a channel.
13023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @throws IllegalArgumentException if the argument is {@code null}.
13033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
13043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(Uri channelUri) {
13051a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            tune(channelUri, null);
13061a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        }
13071a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
13081a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        /**
13091a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * Tunes to a given channel.
13101a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         *
13111a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param channelUri The URI of a channel.
13121a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param params A set of extra parameters which might be handled with this tune event.
13131a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @throws IllegalArgumentException if {@code channelUri} is {@code null}.
13141a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @hide
13151a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         */
13161a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        @SystemApi
13171a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(Uri channelUri, Bundle params) {
13183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (channelUri == null) {
13193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new IllegalArgumentException("channelUri cannot be null");
13203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
13219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1322dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1323dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
13249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
13266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
13276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
13286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
13296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedAudioTrackId = null;
13306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedVideoTrackId = null;
13316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedSubtitleTrackId = null;
13326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoWidth = 0;
13336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoHeight = 0;
13346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
13353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
13361a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mService.tune(mToken, channelUri, params, mUserId);
13373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
13383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throw new RuntimeException(e);
13393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
13403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
13419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
13432c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * Enables or disables the caption for this session.
13442c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         *
13452c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * @param enabled {@code true} to enable, {@code false} to disable.
13462c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         */
13472c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(boolean enabled) {
13482c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            if (mToken == null) {
13492c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Log.w(TAG, "The session has been already released");
13502c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                return;
13512c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13522c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
13532c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                mService.setCaptionEnabled(mToken, enabled, mUserId);
13542c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } catch (RemoteException e) {
13552c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                throw new RuntimeException(e);
13562c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13572c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
13582c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
13592c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        /**
13601f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Selects a track.
13611f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
136210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the track to select. The type can be
136310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
136410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
136510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the track to select. When {@code null}, the currently selected
136610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track of the given type will be unselected.
13675b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @see #getTracks
13681f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
136910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(int type, String trackId) {
13706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
13716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
13726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mAudioTracks, trackId)) {
13736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid audio trackId: " + trackId);
13746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
13776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mVideoTracks, trackId)) {
13786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid video trackId: " + trackId);
13796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
13826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mSubtitleTracks, trackId)) {
13836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid subtitle trackId: " + trackId);
13846320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
13856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
13866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else {
13876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    throw new IllegalArgumentException("invalid type: " + type);
138810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
13891f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13901f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            if (mToken == null) {
13911f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Log.w(TAG, "The session has been already released");
13921f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                return;
13931f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13941f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
139510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                mService.selectTrack(mToken, type, trackId, mUserId);
13961f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } catch (RemoteException e) {
13971f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                throw new RuntimeException(e);
13981f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13991f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
14001f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1401984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        private boolean containsTrack(List<TvTrackInfo> tracks, String trackId) {
1402984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            for (TvTrackInfo track : tracks) {
1403984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                if (track.getId().equals(trackId)) {
1404984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                    return true;
1405984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                }
1406984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            }
1407984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            return false;
1408984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        }
1409984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee
14101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
141110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the list of tracks for a given type. Returns {@code null} if the information is
141210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available.
14131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
141410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
141510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
141610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @return the list of tracks for the given type.
14171f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
141810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public List<TvTrackInfo> getTracks(int type) {
14196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
14216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mAudioTracks == null) {
14226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mAudioTracks);
14256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
14266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mVideoTracks == null) {
14276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mVideoTracks);
14306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
14316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mSubtitleTracks == null) {
14326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
14336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return new ArrayList<TvTrackInfo>(mSubtitleTracks);
143510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
14361f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
143710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
14381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
14391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1440d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
144110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the selected track for a given type. Returns {@code null} if the information is
144210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available or any of the tracks for the given type is not selected.
144310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *
144410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @return the ID of the selected track.
144510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @see #selectTrack
1446d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
144710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public String getSelectedTrack(int type) {
14486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
14506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedAudioTrackId;
14516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
14526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedVideoTrackId;
14536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
14546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedSubtitleTrackId;
14556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
1456d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
145710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
14581f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
14591f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
14601f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
14616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTracksChanged() and updates the internal track information. Returns true if
14626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * there is an update.
14636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
14646320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTracks(List<TvTrackInfo> tracks) {
14656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
14676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
14686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
14696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                for (TvTrackInfo track : tracks) {
14706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (track.getType() == TvTrackInfo.TYPE_AUDIO) {
14716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mAudioTracks.add(track);
14726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_VIDEO) {
14736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mVideoTracks.add(track);
14746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) {
14756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mSubtitleTracks.add(track);
14766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
14776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
14786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return !mAudioTracks.isEmpty() || !mVideoTracks.isEmpty()
14796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        || !mSubtitleTracks.isEmpty();
14806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
14816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
14826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
14836320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
14846320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTrackSelected() and updates the internal track selection information.
14856320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns true if there is an update.
14866320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
14876320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTrackSelection(int type, String trackId) {
14886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
14896320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO && trackId != mSelectedAudioTrackId) {
14906320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedAudioTrackId = trackId;
14916320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14926320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO && trackId != mSelectedVideoTrackId) {
14936320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedVideoTrackId = trackId;
14946320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14956320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE
14966320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        && trackId != mSelectedSubtitleTrackId) {
14976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedSubtitleTrackId = trackId;
14986320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
14996320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
15006320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
15016320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return false;
15026320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
15036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
15046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
15056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns the new/updated video track that contains new video size information. Returns
15066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * null if there is no video track to notify. Subsequent calls of this method results in a
15076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * non-null video track returned only by the first call and null returned by following
15086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * calls. The caller should immediately notify of the video size change upon receiving the
15096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * track.
15106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
15116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        TvTrackInfo getVideoTrackToNotify() {
15126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            synchronized (mTrackLock) {
15136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (!mVideoTracks.isEmpty() && mSelectedVideoTrackId != null) {
15146320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    for (TvTrackInfo track : mVideoTracks) {
15156320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        if (track.getId().equals(mSelectedVideoTrackId)) {
15166320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoWidth = track.getVideoWidth();
15176320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoHeight = track.getVideoHeight();
15186320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            if (mVideoWidth != videoWidth || mVideoHeight != videoHeight) {
15196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoWidth = videoWidth;
15206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoHeight = videoHeight;
15216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                return track;
15226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            }
15236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        }
15246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
15256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
15266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
15276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return null;
15286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
15296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
15306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
15311f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
1532a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * TvInputService.Session.appPrivateCommand()} on the current TvView.
1533a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *
1534a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param action Name of the command to be performed. This <em>must</em> be a scoped name,
1535a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            i.e. prefixed with a package name you own, so that different developers will
1536a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            not create conflicting commands.
1537a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param data Any data to include with the command.
1538a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @hide
1539a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         */
1540a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @SystemApi
1541a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(String action, Bundle data) {
1542a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            if (mToken == null) {
1543a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Log.w(TAG, "The session has been already released");
1544a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                return;
1545a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1546a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1547a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                mService.sendAppPrivateCommand(mToken, action, data, mUserId);
1548a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } catch (RemoteException e) {
1549a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                throw new RuntimeException(e);
1550a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1551a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1552a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1553a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        /**
15549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView}
15559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * should be called whenever the layout of its containing view is changed.
15569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * {@link #removeOverlayView()} should be called to remove the overlay view.
15579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Since a session can have only one overlay view, this method should be called only once
15589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * or it can be called again after calling {@link #removeOverlayView()}.
15599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
15609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param view A view playing TV.
15619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A position of the overlay view.
15629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @throws IllegalArgumentException if any of the arguments is {@code null}.
1563dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim         * @throws IllegalStateException if {@code view} is not attached to a window.
15649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
15659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void createOverlayView(View view, Rect frame) {
15669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (view == null) {
15679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("view cannot be null");
15689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (frame == null) {
15709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("frame cannot be null");
15719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (view.getWindowToken() == null) {
15739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalStateException("view must be attached to a window");
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.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
15819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
15829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
15839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
15859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
15869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
15879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Relayouts the current overlay view.
15889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
15899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A new position of the overlay view.
15909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @throws IllegalArgumentException if the arguments is {@code null}.
15919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
15929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void relayoutOverlayView(Rect frame) {
15939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (frame == null) {
15949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalArgumentException("frame cannot be null");
15959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
15969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1597dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1598dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
15999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
16009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
16019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.relayoutOverlayView(mToken, frame, mUserId);
16029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
16039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
16049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
16059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
16069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
16079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
16089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Removes the current overlay view.
16099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
16109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void removeOverlayView() {
16119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1612dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1613dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
16149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
16159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
16169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.removeOverlayView(mToken, mUserId);
16179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
16189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new RuntimeException(e);
16199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
16209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
16216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
16239bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim         * Requests to unblock content blocked by parental controls.
1624903d6b72cd572665309633e925485464d08bb25aJaewan Kim         */
16259bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        void requestUnblockContent(TvContentRating unblockedRating) {
1626903d6b72cd572665309633e925485464d08bb25aJaewan Kim            if (mToken == null) {
1627903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Log.w(TAG, "The session has been already released");
1628903d6b72cd572665309633e925485464d08bb25aJaewan Kim                return;
1629903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1630a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim            if (unblockedRating == null) {
1631a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim                throw new IllegalArgumentException("unblockedRating cannot be null");
1632a42be3c95021c5fb7e4ac0a8fbfc542f841f44ddJaewan Kim            }
1633903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
16349bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                mService.requestUnblockContent(mToken, unblockedRating.flattenToString(), mUserId);
1635903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } catch (RemoteException e) {
1636903d6b72cd572665309633e925485464d08bb25aJaewan Kim                throw new RuntimeException(e);
1637903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1638903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1639903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1640903d6b72cd572665309633e925485464d08bb25aJaewan Kim        /**
16416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Dispatches an input event to this session.
16426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
16438e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param event An {@link InputEvent} to dispatch.
16446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param token A token used to identify the input event later in the callback.
16456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param callback A callback used to receive the dispatch result.
16468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param handler A {@link Handler} that the dispatch result will be delivered to.
16476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns
16486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns
16496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will
16506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         be invoked later.
16516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @throws IllegalArgumentException if any of the necessary arguments is {@code null}.
16526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
16536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
16546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public int dispatchInputEvent(InputEvent event, Object token,
16556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                FinishedInputEventCallback callback, Handler handler) {
16566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (event == null) {
16576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                throw new IllegalArgumentException("event cannot be null");
16586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (callback != null && handler == null) {
16606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                throw new IllegalArgumentException("handler cannot be null");
16616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
16636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mChannel == null) {
16646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_NOT_HANDLED;
16656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                PendingEvent p = obtainPendingEventLocked(event, token, callback, handler);
16676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (Looper.myLooper() == Looper.getMainLooper()) {
16686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    // Already running on the main thread so we can send the event immediately.
16696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return sendInputEventOnMainLooperLocked(p);
16706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
16716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the main thread.
16736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p);
16746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
16756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandler.sendMessage(msg);
16766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return DISPATCH_IN_PROGRESS;
16776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
16786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
16796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
16816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Callback that is invoked when an input event that was dispatched to this session has been
16826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * finished.
16836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
16846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
16856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
16866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public interface FinishedInputEventCallback {
16876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            /**
16886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * Called when the dispatched input event is finished.
16896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *
16908e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim             * @param token A token passed to {@link #dispatchInputEvent}.
16916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * @param handled {@code true} if the dispatched input event was handled properly.
16926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *            {@code false} otherwise.
16936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             */
16946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void onFinishedInputEvent(Object token, boolean handled);
16956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
16966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
16976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Must be called on the main looper
16986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
16996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
17006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int result = sendInputEventOnMainLooperLocked(p);
17016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (result == DISPATCH_IN_PROGRESS) {
17026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return;
17036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, false);
17076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private int sendInputEventOnMainLooperLocked(PendingEvent p) {
17106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (mChannel != null) {
17116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender == null) {
17126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mSender = new TvInputEventSender(mChannel, mHandler.getLooper());
17136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final InputEvent event = p.mEvent;
17166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final int seq = event.getSequenceNumber();
17176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender.sendInputEvent(seq, event)) {
17186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mPendingEvents.put(seq, p);
17196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
17206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    msg.setAsynchronous(true);
17216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT);
17226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_IN_PROGRESS;
17236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:"
17266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        + event);
17276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return DISPATCH_NOT_HANDLED;
17296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void finishedInputEvent(int seq, boolean handled, boolean timeout) {
17326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final PendingEvent p;
17336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
17346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int index = mPendingEvents.indexOfKey(seq);
17356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (index < 0) {
17366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return; // spurious, event already finished or timed out
17376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = mPendingEvents.valueAt(index);
17406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mPendingEvents.removeAt(index);
17416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (timeout) {
17436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Log.w(TAG, "Timeout waiting for seesion to handle input event after "
17446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                            + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken);
17456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                } else {
17466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
17476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
17486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, handled);
17516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Assumes the event has already been removed from the queue.
17546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
17556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mHandled = handled;
17565b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            if (p.mEventHandler.getLooper().isCurrentThread()) {
17576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Already running on the callback handler thread so we can send the callback
17586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // immediately.
17596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p.run();
17606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            } else {
17616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the callback handler thread.
17626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // In this case, the callback will be responsible for recycling the event.
17635b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                Message msg = Message.obtain(p.mEventHandler, p);
17646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
17656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
17666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void flushPendingEventsLocked() {
17706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
17716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final int count = mPendingEvents.size();
17736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            for (int i = 0; i < count; i++) {
17746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int seq = mPendingEvents.keyAt(i);
17756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0);
17766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
17776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
17786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
17826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                FinishedInputEventCallback callback, Handler handler) {
17836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            PendingEvent p = mPendingEventPool.acquire();
17846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (p == null) {
17856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = new PendingEvent();
17866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
17876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mEvent = event;
17885b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventToken = token;
17896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mCallback = callback;
17905b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventHandler = handler;
17916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return p;
17926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void recyclePendingEventLocked(PendingEvent p) {
17956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.recycle();
17966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mPendingEventPool.release(p);
17976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
17986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
1799bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        IBinder getToken() {
1800bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            return mToken;
1801bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        }
1802bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang
18032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private void releaseInternal() {
18042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mToken = null;
18052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mHandler) {
18062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mChannel != null) {
18072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (mSender != null) {
18082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        flushPendingEventsLocked();
18092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender.dispose();
18102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender = null;
18112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
18122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel.dispose();
18132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel = null;
18142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
18152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mSessionCallbackRecordMap) {
18172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSessionCallbackRecordMap.remove(mSeq);
18182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
18202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
18216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class InputEventHandler extends Handler {
18226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_SEND_INPUT_EVENT = 1;
18236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
18246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_FLUSH_INPUT_EVENT = 3;
18256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            InputEventHandler(Looper looper) {
18276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(looper, null, true);
18286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void handleMessage(Message msg) {
18326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                switch (msg.what) {
18336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_SEND_INPUT_EVENT: {
18346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj);
18356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_TIMEOUT_INPUT_EVENT: {
18386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, true);
18396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_FLUSH_INPUT_EVENT: {
18426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, false);
18436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
18446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
18456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
18466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class TvInputEventSender extends InputEventSender {
18506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public TvInputEventSender(InputChannel inputChannel, Looper looper) {
18516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(inputChannel, looper);
18526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void onInputEventFinished(int seq, boolean handled) {
18566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                finishedInputEvent(seq, handled, false);
18576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class PendingEvent implements Runnable {
18616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public InputEvent mEvent;
18625b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Object mEventToken;
18636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public FinishedInputEventCallback mCallback;
18645b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Handler mEventHandler;
18656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public boolean mHandled;
18666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void recycle() {
18686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mEvent = null;
18695b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventToken = null;
18706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mCallback = null;
18715b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventHandler = null;
18726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandled = false;
18736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
18766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void run() {
18775b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mCallback.onFinishedInputEvent(mEventToken, mHandled);
18786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
18795b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                synchronized (mEventHandler) {
18806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    recyclePendingEventLocked(this);
18816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
18826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
18836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
18843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1885d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1886d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1887d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * The Hardware provides the per-hardware functionality of TV hardware.
1888d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1889d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * TV hardware is physical hardware attached to the Android device; for example, HDMI ports,
1890d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Component/Composite ports, etc. Specifically, logical devices such as HDMI CEC logical
1891d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * devices don't fall into this category.
1892d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1893d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1894d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1895d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
1896d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public final static class Hardware {
1897d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private final ITvInputHardware mInterface;
1898d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1899d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private Hardware(ITvInputHardware hardwareInterface) {
1900d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mInterface = hardwareInterface;
1901d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1902d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1903d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private ITvInputHardware getInterface() {
1904d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mInterface;
1905d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1906d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1907d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean setSurface(Surface surface, TvStreamConfig config) {
1908d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1909d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.setSurface(surface, config);
1910d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1911d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1912d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1913d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1914d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1915d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void setStreamVolume(float volume) {
1916d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1917d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.setStreamVolume(volume);
1918d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1919d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1920d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1921d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1922d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1923d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean dispatchKeyEventToHdmi(KeyEvent event) {
1924d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1925d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.dispatchKeyEventToHdmi(event);
1926d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1927d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1928d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1929d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1930d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1931d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
1932d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                int channelMask, int format) {
1933d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
1934d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.overrideAudioSink(audioType, audioAddress, samplingRate, channelMask,
1935d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                        format);
1936d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
1937d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
1938d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
1939d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1940d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
19413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
1942