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
19a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seoimport android.annotation.IntDef;
20c8b7356434f665c494504661a943323c0bbe702eJae Seoimport android.annotation.NonNull;
214bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kangimport android.annotation.Nullable;
2289813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kangimport android.annotation.RequiresPermission;
23a759b111a1c9cb00284038f8a1554bf29709b952Jae Seoimport android.annotation.SystemApi;
24d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.annotation.SystemService;
25d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkeyimport android.content.Context;
26558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chenimport android.content.Intent;
279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
284b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seoimport android.media.PlaybackParams;
293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
30832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Handler;
323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.os.Looper;
346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.os.Message;
3558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chungimport android.os.ParcelFileDescriptor;
363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
37777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seoimport android.text.TextUtils;
38969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.util.ArrayMap;
393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.Log;
406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.util.Pools.Pool;
416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.util.Pools.SimplePool;
423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEvent;
456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEventSender;
46d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kimimport android.view.KeyEvent;
473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.View;
493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
50de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seoimport com.android.internal.util.Preconditions;
51de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo
52a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seoimport java.lang.annotation.Retention;
53a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seoimport java.lang.annotation.RetentionPolicy;
543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Iterator;
56969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport java.util.LinkedList;
573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/**
613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Central system API to the overall TV input framework (TIF) architecture, which arbitrates
62d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey * interaction between applications and the selected TV inputs.
635557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang *
645557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * <p>There are three primary parties involved in the TV input framework (TIF) architecture:
655557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang *
665557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * <ul>
675557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * <li>The <strong>TV input manager</strong> as expressed by this class is the central point of the
685557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * system that manages interaction between all other parts. It is expressed as the client-side API
695557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * here which exists in each application context and communicates with a global system service that
705557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * manages the interaction across all processes.
715557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * <li>A <strong>TV input</strong> implemented by {@link TvInputService} represents an input source
725557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * of TV, which can be a pass-through input such as HDMI, or a tuner input which provides broadcast
735557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * TV programs. The system binds to the TV input per application’s request.
745557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * on implementing TV inputs.
755557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * <li><strong>Applications</strong> talk to the TV input manager to list TV inputs and check their
765557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * status. Once an application find the input to use, it uses {@link TvView} or
775557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * {@link TvRecordingClient} for further interaction such as watching and recording broadcast TV
785557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * programs.
795557bef5e47fb7a70cd2be03384863ad9f9c5a14Dongwon Kang * </ul>
803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */
81d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey@SystemService(Context.TV_INPUT_SERVICE)
823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManager {
833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManager";
843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    static final int DVB_DEVICE_START = 0;
8658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    static final int DVB_DEVICE_END = 2;
8758739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung
8858739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    /**
8958739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * A demux device of DVB API for controlling the filters of DVB hardware/software.
9058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @hide
9158739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     */
9258739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    public static final int DVB_DEVICE_DEMUX = DVB_DEVICE_START;
9358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     /**
9458739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * A DVR device of DVB API for reading transport streams.
9558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @hide
9658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     */
9758739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    public static final int DVB_DEVICE_DVR = 1;
9858739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    /**
9958739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * A frontend device of DVB API for controlling the tuner and DVB demodulator hardware.
10058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @hide
10158739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     */
10258739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END;
10358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung
104cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    /** @hide */
105cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @Retention(RetentionPolicy.SOURCE)
106cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
107cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo            VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
108cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo            VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
109cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public @interface VideoUnavailableReason {}
110cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo
1116057102dbb746593a7d59cf377c969b62e38c664Jae Seo    static final int VIDEO_UNAVAILABLE_REASON_START = 0;
112ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang    static final int VIDEO_UNAVAILABLE_REASON_END = 4;
1136057102dbb746593a7d59cf377c969b62e38c664Jae Seo
1149b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
115e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
116e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
117e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * an unspecified error.
1189b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
1196057102dbb746593a7d59cf377c969b62e38c664Jae Seo    public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = VIDEO_UNAVAILABLE_REASON_START;
1209b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
121e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
122e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
123e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * the corresponding TV input is in the middle of tuning to a new channel.
1249b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
1256e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo    public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1;
1269b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
127e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
128e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable due to
129e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * weak TV signal.
1309b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
1319b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2;
1329b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang    /**
133e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
134e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
135e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * the corresponding TV input has stopped playback temporarily to buffer more data.
1369b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang     */
137ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang    public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3;
138ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang    /**
139e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
140e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
141e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * the current TV program is audio-only.
142ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang     */
143ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang    public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
1449b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
1453b9be6700fd631e25559693820d03389f8de3893Jae Seo    /** @hide */
1463b9be6700fd631e25559693820d03389f8de3893Jae Seo    @Retention(RetentionPolicy.SOURCE)
147cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
148cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo            TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
149cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public @interface TimeShiftStatus {}
1503b9be6700fd631e25559693820d03389f8de3893Jae Seo
1516f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
152e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
153e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Unknown status. Also
154e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * the status prior to calling {@code notifyTimeShiftStatusChanged}.
1556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
15682fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo    public static final int TIME_SHIFT_STATUS_UNKNOWN = 0;
1576f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
1586f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
159e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
160e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: The current TV input
161e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * does not support time shifting.
1626f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
163465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1;
1646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
1656f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    /**
166e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
167e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
168e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * currently unavailable but might work again later.
1696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang     */
170465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2;
171465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo
172465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo    /**
173e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
174e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)}: Time shifting is
175e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * currently available. In this status, the application assumes it can pause/resume playback,
176e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * seek to a specified time position and set playback rate and audio mode.
177465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo     */
17882fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo    public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
1796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
180e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo    /**
181e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
182e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
183e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * yet started.
184e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     */
1856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang    public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
1866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
187cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    /** @hide */
188cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @Retention(RetentionPolicy.SOURCE)
189cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
190cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo            RECORDING_ERROR_RESOURCE_BUSY})
191cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public @interface RecordingError {}
192cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo
193150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang    static final int RECORDING_ERROR_START = 0;
194150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang    static final int RECORDING_ERROR_END = 2;
195150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang
196969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
197e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
198e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
199ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * completed due to a problem that does not fit under any other error codes, or the error code
200ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * for the problem is defined on the higher version than application's
201ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * <code>android:targetSdkVersion</code>.
202a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     */
203150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang    public static final int RECORDING_ERROR_UNKNOWN = RECORDING_ERROR_START;
204a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
205a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /**
206e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
207e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed due to
208e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * insufficient storage space.
209a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     */
21025c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo    public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1;
211e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo
212e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo    /**
213e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
214e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed because
215e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * a required recording resource was not able to be allocated.
216e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     */
217150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang    public static final int RECORDING_ERROR_RESOURCE_BUSY = RECORDING_ERROR_END;
218a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
219a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /** @hide */
220a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    @Retention(RetentionPolicy.SOURCE)
221cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
222cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo    public @interface InputState {}
223a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
224a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /**
225e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * State for {@link #getInputState(String)} and
226e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected.
22782fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     *
2282375a2e4157cc0c887959976036c60443bfcf908Dongwon Kang     * <p>This state indicates that a source device is connected to the input port and is in the
22971d5c76f19e8714102073bf774c025d5ccdebc11Shubang     * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input.
23071d5c76f19e8714102073bf774c025d5ccdebc11Shubang     * Non-hardware inputs are considered connected all the time.
231969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
232969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED = 0;
233e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo
234969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
235e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * State for {@link #getInputState(String)} and
236e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected but
237e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * in standby mode.
23882fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     *
2392375a2e4157cc0c887959976036c60443bfcf908Dongwon Kang     * <p>This state indicates that a source device is connected to the input port but is in standby
24071d5c76f19e8714102073bf774c025d5ccdebc11Shubang     * or low power mode. It is mostly relevant to hardware inputs such as HDMI input and Component
24171d5c76f19e8714102073bf774c025d5ccdebc11Shubang     * inputs.
242969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
243969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_CONNECTED_STANDBY = 1;
244e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo
245969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    /**
246e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * State for {@link #getInputState(String)} and
247e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo     * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is disconnected.
24882fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     *
24982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * <p>This state indicates that a source device is disconnected from the input port. It is
25082fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * mostly relevant to hardware inputs such as HDMI input.
25182fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     *
252969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     */
253969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    public static final int INPUT_STATE_DISCONNECTED = 2;
254969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
255783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
256783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the user blocked content ratings change. For use with the
257783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isRatingBlocked}.
258783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
259783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_BLOCKED_RATINGS_CHANGED =
2602778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
261783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
262783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
263783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Broadcast intent action when the parental controls enabled state changes. For use with the
264783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * {@link #isParentalControlsEnabled}.
265783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
266783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public static final String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED =
2672778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
2689c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
2699c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
2709c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Broadcast intent action used to query available content rating systems.
2710610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
2720610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>The TV input manager service locates available content rating systems by querying
2730610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * broadcast receivers that are registered for this action. An application can offer additional
2740610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * content rating systems to the user by declaring a suitable broadcast receiver in its
2750610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * manifest.
2760610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
2770610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Here is an example broadcast receiver declaration that an application might include in its
2789c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * AndroidManifest.xml to advertise custom content rating systems. The meta-data specifies a
2799c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * resource that contains a description of each content rating system that is provided by the
2809c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * application.
2810610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
2829c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <p><pre class="prettyprint">
2839c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * {@literal
2849c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * <receiver android:name=".TvInputReceiver">
2859c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <intent-filter>
2869c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *         <action android:name=
2874e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *                 "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
2889c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     </intent-filter>
2899c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *     <meta-data
2904e389e557efb7806b73d2059d46e2809c1a9f83dSungsoo Lim     *             android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
2919c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *             android:resource="@xml/tv_content_rating_systems" />
2920610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * </receiver>}</pre>
2930610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
2940610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>In the above example, the <code>@xml/tv_content_rating_systems</code> resource refers to an
2959c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * XML resource whose root element is <code>&lt;rating-system-definitions&gt;</code> that
2969c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * contains zero or more <code>&lt;rating-system-definition&gt;</code> elements. Each <code>
2979c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * &lt;rating-system-definition&gt;</code> element specifies the ratings, sub-ratings and rating
2989c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * orders of a particular content rating system.
2999c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     *
3009c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * @see TvContentRating
3019c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
3029c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String ACTION_QUERY_CONTENT_RATING_SYSTEMS =
3032778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
3049c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
3059c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    /**
3069c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Content rating systems metadata associated with {@link #ACTION_QUERY_CONTENT_RATING_SYSTEMS}.
3070610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
3080610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>Specifies the resource ID of an XML resource that describes the content rating systems
3090610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * that are provided by the application.
3109c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     */
3119c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public static final String META_DATA_CONTENT_RATING_SYSTEMS =
3122778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
313783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
314a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo    /**
315a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo     * Activity action to set up channel sources i.e.&nbsp;TV inputs of type
316a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo     * {@link TvInputInfo#TYPE_TUNER}. When invoked, the system will display an appropriate UI for
317a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo     * the user to initiate the individual setup flow provided by
318a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo     * {@link android.R.attr#setupActivity} of each TV input service.
319a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo     */
320a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo    public static final String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
321a6d34ee8b4cbcda514274272188414f5ef107450Jae Seo
322e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee    /**
323e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee     * Activity action to display the recording schedules. When invoked, the system will display an
324e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee     * appropriate UI to browse the schedules.
325e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee     */
326e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee    public static final String ACTION_VIEW_RECORDING_SCHEDULES =
327e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee            "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
328e0712b2661e5ec14fdd0ddf91dc42367d3598dc0Chulwoo Lee
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputManager mService;
3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
331969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private final Object mLock = new Object();
332969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
3336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
334093d994965bef197fb676731fc50f6f6f630b8feJae Seo    private final List<TvInputCallbackRecord> mCallbackRecords = new LinkedList<>();
335969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
336969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    // A mapping from TV input ID to the state of corresponding input.
3376320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo    // @GuardedBy("mLock")
338093d994965bef197fb676731fc50f6f6f630b8feJae Seo    private final Map<String, Integer> mStateMap = new ArrayMap<>();
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // A mapping from the sequence number of a session to its SessionCallbackRecord.
3412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
342093d994965bef197fb676731fc50f6f6f630b8feJae Seo            new SparseArray<>();
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A sequence number for the next session to be created. Should be protected by a lock
3452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    // {@code mSessionCallbackRecordMap}.
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mNextSeq;
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final ITvInputClient mClient;
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final int mUserId;
3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Interface used to receive the created session.
354b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
3562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    public abstract static class SessionCallback {
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * This is called after {@link TvInputManager#createSession} has been processed.
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param session A {@link TvInputManager.Session} instance created. This can be
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *            {@code null} if the creation request failed.
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
3634bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang        public void onSessionCreated(@Nullable Session session) {
3642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
3652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        /**
3672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This is called when {@link TvInputManager.Session} is released.
3682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * This typically happens when the process hosting the session has crashed or been killed.
3692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         *
3702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         * @param session A {@link TvInputManager.Session} instance released.
3712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim         */
3722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void onSessionReleased(Session session) {
3732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
374832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
375832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
3761f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the channel of this session is changed by the underlying TV input
3776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * without any {@link TvInputManager.Session#tune(Uri)} request.
378a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         *
379d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
3801f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param channelUri The URI of a channel.
381a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang         */
3821f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void onChannelRetuned(Session session, Uri channelUri) {
383832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
384832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
385832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        /**
3861f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * This is called when the track information of the session has been changed.
387b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         *
388d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
3891f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         * @param tracks A list which includes track information.
390b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang         */
39110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void onTracksChanged(Session session, List<TvTrackInfo> tracks) {
392b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
393b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
394b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        /**
39510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * This is called when a track for a given type is selected.
3969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
3976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
39810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the selected track. The type can be
39910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
40010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
40110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the selected track. When {@code null} the currently selected
40210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track for a given type should be unselected.
403d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
4044bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang        public void onTrackSelected(Session session, int type, @Nullable String trackId) {
405d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
406d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
407d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
4086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * This is invoked when the video size has been changed. It is also called when the first
4096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * time video size information becomes available after the session is tuned to a specific
4106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * channel.
4116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         *
4126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
4136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param width The width of the video.
4146320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * @param height The height of the video.
4156320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
4166320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        public void onVideoSizeChanged(Session session, int width, int height) {
4176320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
4186320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
4196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
420d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * This is called when the video is available, so the TV input starts the playback.
421d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         *
422d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         * @param session A {@link TvInputManager.Session} associated with this callback.
4239b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
4249b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoAvailable(Session session) {
4259b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
4269b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
4279b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
4289b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * This is called when the video is not available, so the TV input stops the playback.
4299b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         *
4306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
4319b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * @param reason The reason why the TV input stopped the playback:
4329b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <ul>
4339b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
4346e62a1508cb7a5efcdde2ae9e51672fea4296dcaJae Seo         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
4359b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
4369b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
437ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
4389b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         * </ul>
4399b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang         */
4409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        public void onVideoUnavailable(Session session, int reason) {
4419b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
4429b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
4439b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        /**
444bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be allowed to watch since
445bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * its content rating is not blocked by parental controls.
446bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         *
4476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
448bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         */
449bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        public void onContentAllowed(Session session) {
450bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
451bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
452bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        /**
453bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * This is called when the current program content turns out to be not allowed to watch
454bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo         * since its content rating is blocked by parental controls.
4556057102dbb746593a7d59cf377c969b62e38c664Jae Seo         *
4566f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
4576057102dbb746593a7d59cf377c969b62e38c664Jae Seo         * @param rating The content ration of the blocked program.
4586057102dbb746593a7d59cf377c969b62e38c664Jae Seo         */
4596057102dbb746593a7d59cf377c969b62e38c664Jae Seo        public void onContentBlocked(Session session, TvContentRating rating) {
4606057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
4616057102dbb746593a7d59cf377c969b62e38c664Jae Seo
4626057102dbb746593a7d59cf377c969b62e38c664Jae Seo        /**
4635b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * This is called when {@link TvInputService.Session#layoutSurface} is called to change the
4645b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * layout of surface.
465ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         *
4666f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
4675b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param left Left position.
4685b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param top Top position.
4695b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param right Right position.
4705b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @param bottom Bottom position.
471ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho         */
472ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
473ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
474ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
475ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        /**
476832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * This is called when a custom event has been sent from this session.
477832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         *
478832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param session A {@link TvInputManager.Session} associated with this callback
479832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventType The type of the event.
480832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         * @param eventArgs Optional arguments of the event.
481832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho         */
482832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
483832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
4846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
4856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
486465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * This is called when the time shift status is changed.
4876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
4886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
489465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @param status The current time shift status. Should be one of the followings.
4906f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <ul>
491465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
4926f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
493465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
4946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * </ul>
4956f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
4966f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStatusChanged(Session session, int status) {
4976f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
4986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
4996f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
5004e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the start position for time shifting has changed.
5016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
5026f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
5034e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
5046f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
5056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
5066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
5076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
5086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
5094e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * This is called when the current position for time shifting is changed.
5106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
5116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * @param session A {@link TvInputManager.Session} associated with this callback.
5124e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
5136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
5146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
5156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
516a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
517e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo        // For the recording session only
518a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
519e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * This is called when the recording session has been tuned to the given channel and is
520e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * ready to start recording.
521b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang         *
522b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang         * @param channelUri The URI of a channel.
523a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
524b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang        void onTuned(Session session, Uri channelUri) {
525a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
526a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
527e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo        // For the recording session only
528a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
529e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * This is called when the current recording session has stopped recording and created a
530e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly
531e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * recorded program.
532a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         *
533e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * @param recordedProgramUri The URI for the newly recorded program.
534a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         **/
535a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void onRecordingStopped(Session session, Uri recordedProgramUri) {
536a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
537a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
538e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo        // For the recording session only
539a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
540e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * This is called when an issue has occurred. It may be called at any time after the current
541e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo         * recording session is created until it is released.
542a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         *
543a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @param error The error code.
544a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
545a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void onError(Session session, @TvInputManager.RecordingError int error) {
546a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
5473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private static final class SessionCallbackRecord {
5502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SessionCallback mSessionCallback;
5513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
5522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session mSession;
5533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        SessionCallbackRecord(SessionCallback sessionCallback,
5553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Handler handler) {
5562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallback = sessionCallback;
5573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionCreated(final Session session) {
5612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSession = session;
5623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
5652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionCreated(session);
5662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
5672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            });
5682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
5692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
5706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionReleased() {
5712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mHandler.post(new Runnable() {
5722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                @Override
5732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                public void run() {
5742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallback.onSessionReleased(mSession);
5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
578832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
5796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postChannelRetuned(final Uri channelUri) {
580832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
581832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
582832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
5831f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    mSessionCallback.onChannelRetuned(mSession, channelUri);
584832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
585832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
586832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
587832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
5886320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTracksChanged(final List<TvTrackInfo> tracks) {
589b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            mHandler.post(new Runnable() {
590b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                @Override
591b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                public void run() {
59210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTracksChanged(mSession, tracks);
593b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
594b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            });
595b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang        }
596b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
5976320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postTrackSelected(final int type, final String trackId) {
598d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            mHandler.post(new Runnable() {
599d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                @Override
600d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                public void run() {
60110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                    mSessionCallback.onTrackSelected(mSession, type, trackId);
602d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
603d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            });
604d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        }
605d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
6066320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoSizeChanged(final int width, final int height) {
6076320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            mHandler.post(new Runnable() {
6086320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                @Override
6096320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                public void run() {
6106320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSessionCallback.onVideoSizeChanged(mSession, width, height);
6116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
6126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            });
6136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
6146320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
6156320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoAvailable() {
6169b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
6179b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
6189b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
6199b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoAvailable(mSession);
6209b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6219b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
6229b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
6239b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postVideoUnavailable(final int reason) {
6259b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            mHandler.post(new Runnable() {
6269b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                @Override
6279b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                public void run() {
6289b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    mSessionCallback.onVideoUnavailable(mSession, reason);
6299b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6309b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            });
6319b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang        }
6329b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentAllowed() {
634bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            mHandler.post(new Runnable() {
635bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                @Override
636bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                public void run() {
637bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    mSessionCallback.onContentAllowed(mSession);
638bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
639bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            });
640bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo        }
641bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
6426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postContentBlocked(final TvContentRating rating) {
6436057102dbb746593a7d59cf377c969b62e38c664Jae Seo            mHandler.post(new Runnable() {
6446057102dbb746593a7d59cf377c969b62e38c664Jae Seo                @Override
6456057102dbb746593a7d59cf377c969b62e38c664Jae Seo                public void run() {
6466057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    mSessionCallback.onContentBlocked(mSession, rating);
6476057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6486057102dbb746593a7d59cf377c969b62e38c664Jae Seo            });
6496057102dbb746593a7d59cf377c969b62e38c664Jae Seo        }
6506057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postLayoutSurface(final int left, final int top, final int right,
652ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                final int bottom) {
653ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            mHandler.post(new Runnable() {
654ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                @Override
655ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                public void run() {
656ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    mSessionCallback.onLayoutSurface(mSession, left, top, right, bottom);
657ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
658ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            });
659ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho        }
660ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
6616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        void postSessionEvent(final String eventType, final Bundle eventArgs) {
662832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            mHandler.post(new Runnable() {
663832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                @Override
664832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                public void run() {
665832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    mSessionCallback.onSessionEvent(mSession, eventType, eventArgs);
666832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
667832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            });
668832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho        }
6696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
6706f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void postTimeShiftStatusChanged(final int status) {
6716f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mHandler.post(new Runnable() {
6726f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                @Override
6736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                public void run() {
6746f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    mSessionCallback.onTimeShiftStatusChanged(mSession, status);
6756f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
6766f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            });
6776f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
6786f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
6796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void postTimeShiftStartPositionChanged(final long timeMs) {
6806f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mHandler.post(new Runnable() {
6816f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                @Override
6826f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                public void run() {
6836f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    mSessionCallback.onTimeShiftStartPositionChanged(mSession, timeMs);
6846f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
6856f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            });
6866f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
6876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
6886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void postTimeShiftCurrentPositionChanged(final long timeMs) {
6896f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            mHandler.post(new Runnable() {
6906f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                @Override
6916f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                public void run() {
6926f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    mSessionCallback.onTimeShiftCurrentPositionChanged(mSession, timeMs);
6936f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
6946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            });
6956f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
696a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
697a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        // For the recording session only
698b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang        void postTuned(final Uri channelUri) {
699a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mHandler.post(new Runnable() {
700a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                @Override
701a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                public void run() {
702b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang                    mSessionCallback.onTuned(mSession, channelUri);
703a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
704a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            });
705a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
706a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
707a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        // For the recording session only
708a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void postRecordingStopped(final Uri recordedProgramUri) {
709a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mHandler.post(new Runnable() {
710a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                @Override
711a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                public void run() {
712a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSessionCallback.onRecordingStopped(mSession, recordedProgramUri);
713a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
714a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            });
715a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
716a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
717a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        // For the recording session only
718a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void postError(final int error) {
719a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mHandler.post(new Runnable() {
720a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                @Override
721a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                public void run() {
722a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mSessionCallback.onError(mSession, error);
723a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
724a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            });
725a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
7263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
72982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * Callback used to monitor status of the TV inputs.
7303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
7312778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    public abstract static class TvInputCallback {
7323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
733969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * This is called when the state of a given TV input is changed.
7343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
735a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @param inputId The ID of the TV input.
7368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         * @param state State of the TV input. The value is one of the following:
737969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <ul>
738969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED}
739969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_CONNECTED_STANDBY}
740969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * <li>{@link TvInputManager#INPUT_STATE_DISCONNECTED}
741969167dc05a6485a32d160895871cff46fd81884Wonsik Kim         * </ul>
7423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
7433b9be6700fd631e25559693820d03389f8de3893Jae Seo        public void onInputStateChanged(String inputId, @InputState int state) {
7443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
74782fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * This is called when a TV input is added to the system.
74882fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         *
74982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * <p>Normally it happens when the user installs a new TV input package that implements
75082fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * {@link TvInputService} interface.
7518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
752a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @param inputId The ID of the TV input.
7538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
7548e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputAdded(String inputId) {
7558e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7568e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7578e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        /**
75882fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * This is called when a TV input is removed from the system.
75982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         *
76082fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * <p>Normally it happens when the user uninstalls the previously installed TV input
76182fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * package.
7628e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         *
763a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @param inputId The ID of the TV input.
7648e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim         */
7658e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        public void onInputRemoved(String inputId) {
7668e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
76719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
76819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        /**
76982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * This is called when a TV input is updated on the system.
77082fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         *
77182fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * <p>Normally it happens when a previously installed TV input package is re-installed or
77282fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo         * the media on which a newer version of the package exists becomes available/unavailable.
77319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         *
774a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @param inputId The ID of the TV input.
77519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee         */
77619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        public void onInputUpdated(String inputId) {
77719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
778a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
779a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
780aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo         * This is called when the information about an existing TV input has been updated.
781a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         *
782aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo         * <p>Because the system automatically creates a <code>TvInputInfo</code> object for each TV
783aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo         * input based on the information collected from the <code>AndroidManifest.xml</code>, this
784dee3cfe897b8cc49a3374807bd61647d429f706fJae Seo         * method is only called back when such information has changed dynamically.
785aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo         *
786aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo         * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
787a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
788aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo        public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
789a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
7903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7922778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo    private static final class TvInputCallbackRecord {
7932778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        private final TvInputCallback mCallback;
7943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Handler mHandler;
7953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7962778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallbackRecord(TvInputCallback callback, Handler handler) {
7972778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallback = callback;
7983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler = handler;
7993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8012778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo        public TvInputCallback getCallback() {
8022778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            return mCallback;
8038e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8048e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
805a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        public void postInputAdded(final String inputId) {
8068e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
8078e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
8088e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
809a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mCallback.onInputAdded(inputId);
8108e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
8118e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
8128e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8138e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
814a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        public void postInputRemoved(final String inputId) {
8158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            mHandler.post(new Runnable() {
8168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                @Override
8178e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                public void run() {
818a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mCallback.onInputRemoved(inputId);
8198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
8208e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            });
8213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
823a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        public void postInputUpdated(final String inputId) {
8243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mHandler.post(new Runnable() {
8253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                @Override
8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                public void run() {
827a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mCallback.onInputUpdated(inputId);
8283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            });
8303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
83119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
832a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        public void postInputStateChanged(final String inputId, final int state) {
83319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            mHandler.post(new Runnable() {
83419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                @Override
83519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                public void run() {
836a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mCallback.onInputStateChanged(inputId, state);
837a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
838a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            });
839a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
840a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
841aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo        public void postTvInputInfoUpdated(final TvInputInfo inputInfo) {
842a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            mHandler.post(new Runnable() {
843a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                @Override
844a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                public void run() {
845aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo                    mCallback.onTvInputInfoUpdated(inputInfo);
84619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
84719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            });
84819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
8503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
852d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Interface used to receive events from Hardware objects.
8530632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
854d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
855d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
856d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
857d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public abstract static class HardwareCallback {
8580632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang        /**
8590632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang         * This is called when {@link Hardware} is no longer available for the client.
8600632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang         */
861d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onReleased();
8620632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang
8630632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang        /**
8640632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang         * This is called when the underlying {@link TvStreamConfig} has been changed.
8650632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang         *
866775e3c288e264399f25ea0ca7e19ac037e5c95b5Dongwon Kang         * @param configs The new {@link TvStreamConfig}s.
8670632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang         */
868d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public abstract void onStreamConfigChanged(TvStreamConfig[] configs);
869d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
870d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
871d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
8723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @hide
8733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
8743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManager(ITvInputManager service, int userId) {
8753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mService = service;
8763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mUserId = userId;
8773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mClient = new ITvInputClient.Stub() {
8783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
879d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
8806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    int seq) {
8812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
8822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
8833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (record == null) {
8843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "Callback not found for " + token);
8853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
8863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Session session = null;
8883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (token != null) {
8892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        session = new Session(token, channel, mService, mUserId, seq,
8902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                                mSessionCallbackRecordMap);
8913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    record.postSessionCreated(session);
8933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
8972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            public void onSessionReleased(int seq) {
8982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                synchronized (mSessionCallbackRecordMap) {
8992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
9002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mSessionCallbackRecordMap.delete(seq);
9012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (record == null) {
9022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Log.e(TAG, "Callback not found for seq:" + seq);
9032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
9042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
9052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.mSession.releaseInternal();
9062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    record.postSessionReleased();
9072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
9082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
9092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
9102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            @Override
9111f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri, int seq) {
912a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mSessionCallbackRecordMap) {
913a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
914a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (record == null) {
915a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
916a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
917a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
9181f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    record.postChannelRetuned(channelUri);
919a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
920a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
921a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
922a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
92310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks, int seq) {
924832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
925832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
926832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
927832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
928832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
929832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
9306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTracks(tracks)) {
9316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTracksChanged(tracks);
9326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
9336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
934b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
935b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
936b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
937b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
93810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId, int seq) {
939d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mSessionCallbackRecordMap) {
940d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
941d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (record == null) {
942d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
943d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
944d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
9456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (record.mSession.updateTrackSelection(type, trackId)) {
9466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        record.postTrackSelected(type, trackId);
9476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        postVideoSizeChangedIfNeededLocked(record);
9486320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
9496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
9506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
9516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
9526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            private void postVideoSizeChangedIfNeededLocked(SessionCallbackRecord record) {
9536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                TvTrackInfo track = record.mSession.getVideoTrackToNotify();
9546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (track != null) {
9556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    record.postVideoSizeChanged(track.getVideoWidth(), track.getVideoHeight());
956d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
957d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
958d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
959d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
9609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable(int seq) {
9619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
9629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
9639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
9649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
9659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
9669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
9679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoAvailable();
9689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
9699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
9709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
9729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason, int seq) {
9739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mSessionCallbackRecordMap) {
9749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
9759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (record == null) {
9769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
9779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
9789b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
9799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    record.postVideoUnavailable(reason);
9809b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
9819b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
9829b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
9839b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
984bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed(int seq) {
985bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mSessionCallbackRecordMap) {
986bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
987bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (record == null) {
988bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
989bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
990bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
991bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    record.postContentAllowed();
992bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
993bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
994bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
995bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
9966057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating, int seq) {
9976057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mSessionCallbackRecordMap) {
9986057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
9996057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (record == null) {
10006057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
10016057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
10026057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
10036057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    record.postContentBlocked(TvContentRating.unflattenFromString(rating));
10046057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
10056057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
10066057102dbb746593a7d59cf377c969b62e38c664Jae Seo
10076057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
1008ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom, int seq) {
1009ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mSessionCallbackRecordMap) {
1010ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
1011ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (record == null) {
1012ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
1013ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
1014ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
1015ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    record.postLayoutSurface(left, top, right, bottom);
1016ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
1017ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
1018ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
1019ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
1020832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs, int seq) {
1021832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mSessionCallbackRecordMap) {
1022832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
1023832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (record == null) {
1024832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Log.e(TAG, "Callback not found for seq " + seq);
1025832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
1026832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
1027832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    record.postSessionEvent(eventType, eventArgs);
1028832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
1029832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
10306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
10316f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            @Override
10326f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            public void onTimeShiftStatusChanged(int status, int seq) {
10336f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                synchronized (mSessionCallbackRecordMap) {
10346f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
10356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    if (record == null) {
10366f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
10376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        return;
10386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    }
10396f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    record.postTimeShiftStatusChanged(status);
10406f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
10416f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
10426f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
10436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            @Override
10446f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            public void onTimeShiftStartPositionChanged(long timeMs, int seq) {
10456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                synchronized (mSessionCallbackRecordMap) {
10466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
10476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    if (record == null) {
10486f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
10496f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        return;
10506f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    }
10516f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    record.postTimeShiftStartPositionChanged(timeMs);
10526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
10536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
10546f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
10556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            @Override
10566f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            public void onTimeShiftCurrentPositionChanged(long timeMs, int seq) {
10576f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                synchronized (mSessionCallbackRecordMap) {
10586f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
10596f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    if (record == null) {
10606f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        Log.e(TAG, "Callback not found for seq " + seq);
10616f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                        return;
10626f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    }
10636f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                    record.postTimeShiftCurrentPositionChanged(timeMs);
10646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                }
10656f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
1066a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1067832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
1068b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang            public void onTuned(int seq, Uri channelUri) {
1069a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                synchronized (mSessionCallbackRecordMap) {
1070a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
1071a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    if (record == null) {
1072a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
1073a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        return;
1074a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    }
1075b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang                    record.postTuned(channelUri);
1076a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1077a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
1078a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1079a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            @Override
1080a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            public void onRecordingStopped(Uri recordedProgramUri, int seq) {
1081a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                synchronized (mSessionCallbackRecordMap) {
1082a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
1083a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    if (record == null) {
1084a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
1085a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        return;
10868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
1087a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    record.postRecordingStopped(recordedProgramUri);
10888e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
10898e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
10908e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
10918e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
1092a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            public void onError(int error, int seq) {
1093a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                synchronized (mSessionCallbackRecordMap) {
1094a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
1095a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    if (record == null) {
1096a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        Log.e(TAG, "Callback not found for seq " + seq);
1097a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        return;
1098a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    }
1099a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    record.postError(error);
1100a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1101a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
1102a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        };
1103a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
1104a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            @Override
11058e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputAdded(String inputId) {
11068e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
11078e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.put(inputId, INPUT_STATE_CONNECTED);
11082778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
11098e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputAdded(inputId);
11108e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    }
11118e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                }
11128e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
11138e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
11148e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            @Override
11158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            public void onInputRemoved(String inputId) {
11168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                synchronized (mLock) {
11178e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    mStateMap.remove(inputId);
11182778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
11198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        record.postInputRemoved(inputId);
11203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
112319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
112419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
112519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onInputUpdated(String inputId) {
112619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                synchronized (mLock) {
1127db8f7ab752de641b147015a2b4a134913fbcb594Youngsang Cho                    for (TvInputCallbackRecord record : mCallbackRecords) {
112819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                        record.postInputUpdated(inputId);
112919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    }
113019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
113119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
1132a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1133a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            @Override
1134a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            public void onInputStateChanged(String inputId, int state) {
1135a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                synchronized (mLock) {
1136a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    mStateMap.put(inputId, state);
1137a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
1138a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                        record.postInputStateChanged(inputId, state);
1139a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    }
1140a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1141a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
1142a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1143a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            @Override
1144aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo            public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
1145a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                synchronized (mLock) {
1146a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    for (TvInputCallbackRecord record : mCallbackRecords) {
1147aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo                        record.postTvInputInfoUpdated(inputInfo);
1148a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                    }
1149a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                }
1150a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
11513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1152969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        try {
11539127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            if (mService != null) {
115438b3257b7c0d80d282f1a1f7e1dd9c47e77c1081Jae Seo                mService.registerCallback(managerCallback, mUserId);
1155993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                List<TvInputInfo> infos = mService.getTvInputList(mUserId);
1156993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                synchronized (mLock) {
1157993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                    for (TvInputInfo info : infos) {
1158993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                        String inputId = info.getId();
115982fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo                        mStateMap.put(inputId, mService.getTvInputState(inputId, mUserId));
1160993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                    }
1161993f81e2380da210c27e1e957ac1bdca3a99100aDongwon Kang                }
11629127e4580c618bc1afae5c2c280f5a271f7a7635Jae Seo            }
1163969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } catch (RemoteException e) {
1164c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1165969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
11663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
11673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
11693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * Returns the complete list of TV inputs on the system.
11703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
11713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     * @return List of {@link TvInputInfo} for each TV input that describes its meta information.
11723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
11733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public List<TvInputInfo> getTvInputList() {
11743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
11753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return mService.getTvInputList(mUserId);
11763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
1177c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
11783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
11803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
1182b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * Returns the {@link TvInputInfo} for a given TV input.
1183b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     *
1184b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @param inputId The ID of the TV input.
1185b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     * @return the {@link TvInputInfo} for a given TV input. {@code null} if not found.
1186b375805f3b1672e68d1511565af4700e5fa8491dJae Seo     */
11874bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang    @Nullable
1188c8b7356434f665c494504661a943323c0bbe702eJae Seo    public TvInputInfo getTvInputInfo(@NonNull String inputId) {
1189de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(inputId);
1190b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        try {
1191b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            return mService.getTvInputInfo(inputId, mUserId);
1192b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        } catch (RemoteException e) {
1193c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1194b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
1195b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    }
1196b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
1197b375805f3b1672e68d1511565af4700e5fa8491dJae Seo    /**
1198ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * Updates the <code>TvInputInfo</code> for an existing TV input. A TV input service
1199ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * implementation may call this method to pass the application and system an up-to-date
1200ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * <code>TvInputInfo</code> object that describes itself.
1201c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo     *
1202ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * <p>The system automatically creates a <code>TvInputInfo</code> object for each TV input,
1203ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * based on the information collected from the <code>AndroidManifest.xml</code>, thus it is not
1204ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * necessary to call this method unless such information has changed dynamically.
1205ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * Use {@link TvInputInfo.Builder} to build a new <code>TvInputInfo</code> object.
1206ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     *
1207ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * <p>Attempting to change information about a TV input that the calling package does not own
1208ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * does nothing.
1209c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo     *
1210aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo     * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
1211c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo     * @throws IllegalArgumentException if the argument is {@code null}.
1212ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang     * @see TvInputCallback#onTvInputInfoUpdated(TvInputInfo)
1213c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo     */
1214ee564881d99eeca24e1ef4b59ca6dab4d30a90d9Dongwon Kang    public void updateTvInputInfo(@NonNull TvInputInfo inputInfo) {
1215c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo        Preconditions.checkNotNull(inputInfo);
1216c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo        try {
1217aa5605ffee270ef8802c5d9dc8df8ce71e377f55Jae Seo            mService.updateTvInputInfo(inputInfo, mUserId);
1218c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo        } catch (RemoteException e) {
1219c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1220c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo        }
1221c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo    }
1222c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo
1223c2a89510ddda390d6d53ff24dd20d257fcd2379eJae Seo    /**
122482fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * Returns the state of a given TV input.
122582fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     *
122682fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * <p>The state is one of the following:
1227969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <ul>
1228969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED}
1229969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_CONNECTED_STANDBY}
1230969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * <li>{@link #INPUT_STATE_DISCONNECTED}
1231969167dc05a6485a32d160895871cff46fd81884Wonsik Kim     * </ul>
12323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
1233a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input.
123482fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo     * @throws IllegalArgumentException if the argument is {@code null}.
12353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
12363b9be6700fd631e25559693820d03389f8de3893Jae Seo    @InputState
1237c8b7356434f665c494504661a943323c0bbe702eJae Seo    public int getInputState(@NonNull String inputId) {
1238de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(inputId);
1239969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
1240969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            Integer state = mStateMap.get(inputId);
1241969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (state == null) {
124282fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo                Log.w(TAG, "Unrecognized input ID: " + inputId);
124382fce64530d19a4da1c02d424fb2515feafe6a70Jae Seo                return INPUT_STATE_DISCONNECTED;
12443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1245093d994965bef197fb676731fc50f6f6f630b8feJae Seo            return state;
12463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
12483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
12502778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Registers a {@link TvInputCallback}.
12513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
12522778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback A callback used to monitor status of the TV inputs.
12538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the status change will be delivered to.
12543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
1255c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void registerCallback(@NonNull TvInputCallback callback, @NonNull Handler handler) {
1256de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(callback);
1257de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(handler);
1258969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
12592778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            mCallbackRecords.add(new TvInputCallbackRecord(callback, handler));
12603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
12623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
12642778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * Unregisters the existing {@link TvInputCallback}.
12653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
12662778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo     * @param callback The existing callback to remove.
12673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
1268c8b7356434f665c494504661a943323c0bbe702eJae Seo    public void unregisterCallback(@NonNull final TvInputCallback callback) {
1269de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(callback);
1270969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        synchronized (mLock) {
12712778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo            for (Iterator<TvInputCallbackRecord> it = mCallbackRecords.iterator();
1272969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    it.hasNext(); ) {
12732778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                TvInputCallbackRecord record = it.next();
12742778f5a7bd7c45861b6f2fc5639509e327495a4aJae Seo                if (record.getCallback() == callback) {
12753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    it.remove();
1276969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    break;
12773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
12813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    /**
1283783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the user's parental controls enabled state.
1284783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1285783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the user enabled the parental controls, {@code false} otherwise.
1286783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1287783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public boolean isParentalControlsEnabled() {
1288783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1289783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isParentalControlsEnabled(mUserId);
1290783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1291c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1292783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1293783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1294783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1295783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
1296783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Sets the user's parental controls enabled state.
1297783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1298783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param enabled The user's parental controls enabled state. {@code true} if the user enabled
1299783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *            the parental controls, {@code false} otherwise.
1300783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isParentalControlsEnabled
1301783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
1302783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1303783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
130489813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1305783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public void setParentalControlsEnabled(boolean enabled) {
1306783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1307783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.setParentalControlsEnabled(enabled, mUserId);
1308783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1309c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1310783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1311783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1312783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1313783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
1314783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Checks whether a given TV content rating is blocked by the user.
1315783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1316936c040ec445afad98ec16fc634ae6573eceefbbJae Seo     * @param rating The TV content rating to check. Can be {@link TvContentRating#UNRATED}.
1317783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return {@code true} if the given TV content rating is blocked, {@code false} otherwise.
1318783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1319c8b7356434f665c494504661a943323c0bbe702eJae Seo    public boolean isRatingBlocked(@NonNull TvContentRating rating) {
1320de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(rating);
1321783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1322783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return mService.isRatingBlocked(rating.flattenToString(), mUserId);
1323783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1324c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1325783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1326783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1327783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1328783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
1329783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Returns the list of blocked content ratings.
1330783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1331783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @return the list of content ratings blocked by the user.
1332783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
1333783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1334783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
1335783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    public List<TvContentRating> getBlockedRatings() {
1336783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1337093d994965bef197fb676731fc50f6f6f630b8feJae Seo            List<TvContentRating> ratings = new ArrayList<>();
1338783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            for (String rating : mService.getBlockedRatings(mUserId)) {
1339783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                ratings.add(TvContentRating.unflattenFromString(rating));
1340783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1341783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            return ratings;
1342783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1343c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1344783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1345783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1346783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1347783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
1348783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Adds a user blocked content rating.
1349783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1350783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to block.
1351783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
1352783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #removeBlockedRating
1353783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
1354783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1355783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
135689813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1357de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo    public void addBlockedRating(@NonNull TvContentRating rating) {
1358de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(rating);
1359783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1360783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.addBlockedRating(rating.flattenToString(), mUserId);
1361783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1362c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1363783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1364783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1365783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1366783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
1367783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * Removes a user blocked content rating.
1368783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     *
1369783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @param rating The content rating to unblock.
1370783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #isRatingBlocked
1371783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @see #addBlockedRating
1372783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     * @hide
1373783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo     */
1374783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    @SystemApi
137589813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1376de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo    public void removeBlockedRating(@NonNull TvContentRating rating) {
1377de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(rating);
1378783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        try {
1379783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mService.removeBlockedRating(rating.flattenToString(), mUserId);
1380783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        } catch (RemoteException e) {
1381c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1382783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1383783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    }
1384783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1385783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo    /**
13869c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo     * Returns the list of all TV content rating systems defined.
13875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     * @hide
13885c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim     */
13895c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    @SystemApi
13909c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
13915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        try {
13929c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            return mService.getTvContentRatingSystemList(mUserId);
13935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        } catch (RemoteException e) {
1394c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
13955c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
13965c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    }
13975c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
13985c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim    /**
1399558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * Notifies the TV input of the given preview program that the program's browsable state is
1400558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * disabled.
1401558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * @hide
1402558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     */
1403558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @SystemApi
1404558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
1405558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    public void notifyPreviewProgramBrowsableDisabled(String packageName, long programId) {
1406558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        Intent intent = new Intent();
1407558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setAction(TvContract.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED);
1408558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.putExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, programId);
1409558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setPackage(packageName);
1410558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        try {
1411558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            mService.sendTvInputNotifyIntent(intent, mUserId);
1412558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        } catch (RemoteException e) {
1413558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            throw e.rethrowFromSystemServer();
1414558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        }
1415558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    }
1416558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen
1417558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    /**
1418558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * Notifies the TV input of the given watch next program that the program's browsable state is
1419558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * disabled.
1420558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * @hide
1421558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     */
1422558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @SystemApi
1423558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
1424558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    public void notifyWatchNextProgramBrowsableDisabled(String packageName, long programId) {
1425558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        Intent intent = new Intent();
1426558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setAction(TvContract.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED);
1427558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.putExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, programId);
1428558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setPackage(packageName);
1429558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        try {
1430558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            mService.sendTvInputNotifyIntent(intent, mUserId);
1431558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        } catch (RemoteException e) {
1432558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            throw e.rethrowFromSystemServer();
1433558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        }
1434558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    }
1435558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen
1436558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    /**
1437558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * Notifies the TV input of the given preview program that the program is added to watch next.
1438558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     * @hide
1439558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen     */
1440558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @SystemApi
1441558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
1442558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    public void notifyPreviewProgramAddedToWatchNext(String packageName, long previewProgramId,
1443558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            long watchNextProgramId) {
1444558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        Intent intent = new Intent();
1445558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setAction(TvContract.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT);
1446558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.putExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, previewProgramId);
1447558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.putExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, watchNextProgramId);
1448558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        intent.setPackage(packageName);
1449558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        try {
1450558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            mService.sendTvInputNotifyIntent(intent, mUserId);
1451558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        } catch (RemoteException e) {
1452558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen            throw e.rethrowFromSystemServer();
1453558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen        }
1454558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    }
1455558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen
1456558acf96dbffc0f13b414b1a5c5de191f6ffe27aConrad Chen    /**
1457674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho     * Creates a {@link Session} for a given TV input.
14580610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     *
14590610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>The number of sessions that can be created at the same time is limited by the capability
14600610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * of the given TV input.
14613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     *
1462a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input.
14638e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param callback A callback used to receive the created session.
14648e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim     * @param handler A {@link Handler} that the session creation will be delivered to.
1465b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
14663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo     */
1467de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo    public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback,
1468de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            @NonNull Handler handler) {
1469a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        createSessionInternal(inputId, false, callback, handler);
1470a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    }
1471a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1472a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    /**
1473a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * Creates a recording {@link Session} for a given TV input.
1474a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     *
1475a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * <p>The number of sessions that can be created at the same time is limited by the capability
1476a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * of the given TV input.
1477a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     *
1478a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input.
1479a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param callback A callback used to receive the created session.
1480a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param handler A {@link Handler} that the session creation will be delivered to.
1481a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @hide
1482a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     */
1483a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    public void createRecordingSession(@NonNull String inputId,
1484a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            @NonNull final SessionCallback callback, @NonNull Handler handler) {
1485a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        createSessionInternal(inputId, true, callback, handler);
1486a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    }
1487a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
1488a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo    private void createSessionInternal(String inputId, boolean isRecordingSession,
1489a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            SessionCallback callback, Handler handler) {
1490de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(inputId);
1491de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(callback);
1492de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        Preconditions.checkNotNull(handler);
14932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionCallbackRecord record = new SessionCallbackRecord(callback, handler);
14942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        synchronized (mSessionCallbackRecordMap) {
14953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            int seq = mNextSeq++;
14962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap.put(seq, record);
14973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
1498a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
14993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
1500c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
15013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
15023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
15033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
15043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1505b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo    /**
1506c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Returns the TvStreamConfig list of the given TV input.
1507c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
150890e733385d466acd87730676c83c080a17ff495fWonsik Kim     * If you are using {@link Hardware} object from {@link
150990e733385d466acd87730676c83c080a17ff495fWonsik Kim     * #acquireTvInputHardware}, you should get the list of available streams
151090e733385d466acd87730676c83c080a17ff495fWonsik Kim     * from {@link HardwareCallback#onStreamConfigChanged} method, not from
151190e733385d466acd87730676c83c080a17ff495fWonsik Kim     * here. This method is designed to be used with {@link #captureFrame} in
151290e733385d466acd87730676c83c080a17ff495fWonsik Kim     * capture scenarios specifically and not suitable for any other use.
151390e733385d466acd87730676c83c080a17ff495fWonsik Kim     *
1514a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input.
1515c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return List of {@link TvStreamConfig} which is available for capturing
1516c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *   of the given TV input.
1517c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1518c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1519c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1520d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey    @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT)
1521c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
1522c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1523c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.getAvailableTvStreamConfigList(inputId, mUserId);
1524c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1525c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1526c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1527c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1528c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1529c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1530c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * Take a snapshot of the given TV input into the provided Surface.
1531c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     *
1532a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo     * @param inputId The ID of the TV input.
1533c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param surface the {@link Surface} to which the snapshot is captured.
1534c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @param config the {@link TvStreamConfig} which is used for capturing.
1535c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @return true when the {@link Surface} is ready to be captured.
1536c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     * @hide
1537c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo     */
1538c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    @SystemApi
1539d86b8fea43ebb6e5c31691b44d8ceb0d8d3c9072Jeff Sharkey    @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT)
1540c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
1541c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        try {
1542c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            return mService.captureFrame(inputId, surface, config, mUserId);
1543c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        } catch (RemoteException e) {
1544c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1545df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1546df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    }
1547df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1548df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    /**
1549df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * Returns true if there is only a single TV input session.
1550df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     *
1551df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     * @hide
1552df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo     */
1553df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    @SystemApi
1554df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo    public boolean isSingleSessionActive() {
1555df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        try {
1556df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            return mService.isSingleSessionActive(mUserId);
1557df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        } catch (RemoteException e) {
1558c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1559c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1560c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    }
1561c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1562c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo    /**
1563d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Returns a list of TvInputHardwareInfo objects representing available hardware.
1564d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
1565d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1566d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1567d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
156889813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1569d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public List<TvInputHardwareInfo> getHardwareList() {
1570d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1571d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mService.getHardwareList();
1572d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1573c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1574d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1575d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1576d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1577d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
15780632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * Acquires {@link Hardware} object for the given device ID.
1579d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
15800632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
15810632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * acquired Hardware.
1582d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
15830632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param deviceId The device ID to acquire Hardware for.
15840632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param callback A callback to receive updates on Hardware.
15850632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param info The TV input which will use the acquired Hardware.
15860632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @return Hardware on success, {@code null} otherwise.
15870632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
15880632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @removed
1589d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
159089813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1591d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public Hardware acquireTvInputHardware(int deviceId, final HardwareCallback callback,
1592d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            TvInputInfo info) {
15930632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang        return acquireTvInputHardware(deviceId, info, callback);
15940632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang    }
15950632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang
15960632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang    /**
15970632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * Acquires {@link Hardware} object for the given device ID.
15980632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
15990632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * <p>A subsequent call to this method on the same {@code deviceId} will release the currently
16000632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * acquired Hardware.
16010632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
16020632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param deviceId The device ID to acquire Hardware for.
16030632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param callback A callback to receive updates on Hardware.
16040632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param info The TV input which will use the acquired Hardware.
16050632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @return Hardware on success, {@code null} otherwise.
16060632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
16070632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @hide
16080632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     */
16090632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang    @SystemApi
16100632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
16110632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang    public Hardware acquireTvInputHardware(int deviceId, TvInputInfo info,
16120632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang            final HardwareCallback callback) {
1613d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1614d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return new Hardware(
1615d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    mService.acquireTvInputHardware(deviceId, new ITvInputHardwareCallback.Stub() {
1616d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1617d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onReleased() {
1618d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onReleased();
1619d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1620d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1621d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                @Override
1622d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                public void onStreamConfigChanged(TvStreamConfig[] configs) {
1623d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                    callback.onStreamConfigChanged(configs);
1624d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                }
1625d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }, info, mUserId));
1626d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1627c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1628d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1629d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1630d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1631d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
1632d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Releases previously acquired hardware object.
1633d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
16340632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param deviceId The device ID this Hardware was acquired for
16350632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     * @param hardware Hardware to release.
16360632d8ae71418bea092f9f2c7e62118213e7cc78Dongwon Kang     *
1637d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
1638d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
1639d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
164089813b8162d84c5736d375e6a3018edcae4c97b9Dongwon Kang    @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1641d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public void releaseTvInputHardware(int deviceId, Hardware hardware) {
1642d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        try {
1643d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
1644d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        } catch (RemoteException e) {
1645c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
1646d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
1647d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
1648d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
1649d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
165058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * Returns the list of currently available DVB devices on the system.
165158739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     *
165258739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @return the list of {@link DvbDeviceInfo} objects representing available DVB devices.
165358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @hide
165458739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     */
165558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    public List<DvbDeviceInfo> getDvbDeviceList() {
165658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        try {
165758739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung            return mService.getDvbDeviceList();
165858739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        } catch (RemoteException e) {
1659c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
166058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        }
166158739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    }
166258739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung
166358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    /**
166458739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * Returns a {@link ParcelFileDescriptor} of a specified DVB device for a given
166558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * {@link DvbDeviceInfo}
166658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     *
166758739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @param info A {@link DvbDeviceInfo} to open a DVB device.
1668ed6586a569ddf2cf67014bbf51f8126dff116ca8Jae Seo     * @param device A DVB device. The DVB device can be {@link #DVB_DEVICE_DEMUX},
1669ed6586a569ddf2cf67014bbf51f8126dff116ca8Jae Seo     *            {@link #DVB_DEVICE_DVR} or {@link #DVB_DEVICE_FRONTEND}.
167058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @return a {@link ParcelFileDescriptor} of a specified DVB device for a given
1671ed6586a569ddf2cf67014bbf51f8126dff116ca8Jae Seo     *         {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} was invalid
1672ed6586a569ddf2cf67014bbf51f8126dff116ca8Jae Seo     *         or the specified DVB device was busy with a previous request.
167358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     * @hide
167458739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung     */
167558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) {
167658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        try {
167758739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung            if (DVB_DEVICE_START > device || DVB_DEVICE_END < device) {
167858739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung                throw new IllegalArgumentException("Invalid DVB device: " + device);
167958739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung            }
168058739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung            return mService.openDvbDevice(info, device);
168158739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        } catch (RemoteException e) {
1682c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey            throw e.rethrowFromSystemServer();
168358739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung        }
168458739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    }
168558739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung
168658739e758428f3b880f8e67161f57c59aa06d496Jaesung Chung    /**
16872e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     * Requests to make a channel browsable.
16882e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     *
16892e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     * <p>Once called, the system will review the request and make the channel browsable based on
16902e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     * its policy. The first request from a package is guaranteed to be approved.
16912e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     *
16922e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     * @param channelUri The URI for the channel to be browsable.
16932e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     * @hide
16942e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang     */
16952e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang    public void requestChannelBrowsable(Uri channelUri) {
16962e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang        try {
16972e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang            mService.requestChannelBrowsable(channelUri, mUserId);
16982e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang        } catch (RemoteException e) {
16992e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang            throw e.rethrowFromSystemServer();
17002e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang        }
17012e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang    }
17022e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang
17032e7f5ce709f9ee45c4fb219d768fbec057185375Dongwon Kang    /**
1704b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * The Session provides the per-session functionality of TV inputs.
1705b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     * @hide
1706b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo     */
17073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public static final class Session {
17086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_IN_PROGRESS = -1;
17096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_NOT_HANDLED = 0;
17106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        static final int DISPATCH_HANDLED = 1;
17116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private static final long INPUT_SESSION_NOT_RESPONDING_TIMEOUT = 2500;
17136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ITvInputManager mService;
17153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
17162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mSeq;
17176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // For scheduling input event handling on the main thread. This also serves as a lock to
17196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // protect pending input events and the input channel.
17206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final InputEventHandler mHandler = new InputEventHandler(Looper.getMainLooper());
17216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
1722093d994965bef197fb676731fc50f6f6f630b8feJae Seo        private final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
1723093d994965bef197fb676731fc50f6f6f630b8feJae Seo        private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
17242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
17256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        private IBinder mToken;
17276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private TvInputEventSender mSender;
17286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private InputChannel mChannel;
17296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
17306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        private final Object mMetadataLock = new Object();
17316f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
1732093d994965bef197fb676731fc50f6f6f630b8feJae Seo        private final List<TvTrackInfo> mAudioTracks = new ArrayList<>();
17336f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
1734093d994965bef197fb676731fc50f6f6f630b8feJae Seo        private final List<TvTrackInfo> mVideoTracks = new ArrayList<>();
17356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
1736093d994965bef197fb676731fc50f6f6f630b8feJae Seo        private final List<TvTrackInfo> mSubtitleTracks = new ArrayList<>();
17376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
173810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedAudioTrackId;
17396f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
174010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedVideoTrackId;
17416f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
174210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        private String mSelectedSubtitleTrackId;
17436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
17446320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoWidth;
17456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        // @GuardedBy("mMetadataLock")
17466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        private int mVideoHeight;
17473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
17492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
17503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mToken = token;
17516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mChannel = channel;
17523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mService = service;
17533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
17542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
17552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSessionCallbackRecordMap = sessionCallbackRecordMap;
17563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
17593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Releases this session.
17603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
17613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void release() {
17629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1763dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1764dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
17659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
17663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
17673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.releaseSession(mToken, mUserId);
17683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
1769c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
17703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
17716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
17722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            releaseInternal();
17733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
177615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * Sets this as the main session. The main session is a session whose corresponding TV
177715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * input determines the HDMI-CEC active source device.
177815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         *
177915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee         * @see TvView#setMain
17804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee         */
178115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        void setMain() {
17824c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            if (mToken == null) {
17834c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Log.w(TAG, "The session has been already released");
17844c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                return;
17854c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
17864c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
17874c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                mService.setMainSession(mToken, mUserId);
17884c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } catch (RemoteException e) {
1789c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
17904c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
17914c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
17924c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
17934c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        /**
17943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Sets the {@link android.view.Surface} for this session.
17953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
17963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param surface A {@link android.view.Surface} used to render video.
17973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1798f1c025cbcd98f2366d384c5aac114c330090a645Wonsik Kim        public void setSurface(Surface surface) {
17999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1800dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1801dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
18029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
18033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // surface can be null.
18043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
18053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setSurface(mToken, surface, mUserId);
18063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
1807c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
18083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
1812606c8a396558e9714159db4969340af170677172Jae Seo         * Notifies of any structural changes (format or size) of the surface passed in
1813606c8a396558e9714159db4969340af170677172Jae Seo         * {@link #setSurface}.
1814e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         *
1815606c8a396558e9714159db4969340af170677172Jae Seo         * @param format The new PixelFormat of the surface.
1816606c8a396558e9714159db4969340af170677172Jae Seo         * @param width The new width of the surface.
1817606c8a396558e9714159db4969340af170677172Jae Seo         * @param height The new height of the surface.
1818e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho         */
1819e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(int format, int width, int height) {
1820e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            if (mToken == null) {
1821e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Log.w(TAG, "The session has been already released");
1822e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                return;
1823e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1824e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1825e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
1826e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } catch (RemoteException e) {
1827c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
1828e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1829e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1830e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1831e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        /**
1832782f7345471072b630e58c7abd3579b0015273b1Jae Seo         * Sets the relative stream volume of this session to handle a change of audio focus.
18333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
18343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param volume A volume value between 0.0f to 1.0f.
18353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @throws IllegalArgumentException if the volume value is out of range.
18363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
1837782f7345471072b630e58c7abd3579b0015273b1Jae Seo        public void setStreamVolume(float volume) {
18389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1839dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1840dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
18419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
18423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
18433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (volume < 0.0f || volume > 1.0f) {
18443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    throw new IllegalArgumentException("volume should be between 0.0f and 1.0f");
18453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
18463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mService.setVolume(mToken, volume, mUserId);
18473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
1848c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
18493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        /**
18533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * Tunes to a given channel.
18543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         *
18553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         * @param channelUri The URI of a channel.
18563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo         */
18573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(Uri channelUri) {
18581a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            tune(channelUri, null);
18591a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        }
18601a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
18611a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        /**
18621a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * Tunes to a given channel.
18631a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         *
18641a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param channelUri The URI of a channel.
18651a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         * @param params A set of extra parameters which might be handled with this tune event.
18661a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim         */
1867de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        public void tune(@NonNull Uri channelUri, Bundle params) {
1868de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(channelUri);
18699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
1870dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
1871dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
18729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
18736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
18746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
18756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
18766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
18776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedAudioTrackId = null;
18786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedVideoTrackId = null;
18796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSelectedSubtitleTrackId = null;
18806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoWidth = 0;
18816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoHeight = 0;
18826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
18833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
18841a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                mService.tune(mToken, channelUri, params, mUserId);
18853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } catch (RemoteException e) {
1886c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
18873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
18909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
18912c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * Enables or disables the caption for this session.
18922c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         *
18932c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         * @param enabled {@code true} to enable, {@code false} to disable.
18942c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo         */
18952c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(boolean enabled) {
18962c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            if (mToken == null) {
18972c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Log.w(TAG, "The session has been already released");
18982c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                return;
18992c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
19002c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
19012c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                mService.setCaptionEnabled(mToken, enabled, mUserId);
19022c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } catch (RemoteException e) {
1903c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
19042c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
19052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
19062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
19072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        /**
19081f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Selects a track.
19091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
191010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the track to select. The type can be
191110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
191210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_SUBTITLE}.
191310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param trackId The ID of the track to select. When {@code null}, the currently selected
191410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            track of the given type will be unselected.
19155b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo         * @see #getTracks
19161f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
19174bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang        public void selectTrack(int type, @Nullable String trackId) {
19186f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
19196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
19206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mAudioTracks, trackId)) {
19216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid audio trackId: " + trackId);
19226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
19236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
19246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
19256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mVideoTracks, trackId)) {
19266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid video trackId: " + trackId);
19276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
19286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
19296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
19306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (trackId != null && !containsTrack(mSubtitleTracks, trackId)) {
19316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        Log.w(TAG, "Invalid subtitle trackId: " + trackId);
19326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return;
19336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
19346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else {
19356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    throw new IllegalArgumentException("invalid type: " + type);
193610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
19371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
19381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            if (mToken == null) {
19391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Log.w(TAG, "The session has been already released");
19401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                return;
19411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
19421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
194310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                mService.selectTrack(mToken, type, trackId, mUserId);
19441f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } catch (RemoteException e) {
1945c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
19461f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
19471f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
19481f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1949984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        private boolean containsTrack(List<TvTrackInfo> tracks, String trackId) {
1950984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            for (TvTrackInfo track : tracks) {
1951984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                if (track.getId().equals(trackId)) {
1952984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                    return true;
1953984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee                }
1954984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            }
1955984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee            return false;
1956984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee        }
1957984d99b584b4d24c160a8725e1624c68ac70f122Chulwoo Lee
19581f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
195910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the list of tracks for a given type. Returns {@code null} if the information is
196010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available.
19611f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         *
196210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @param type The type of the tracks. The type can be {@link TvTrackInfo#TYPE_AUDIO},
196310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *            {@link TvTrackInfo#TYPE_VIDEO} or {@link TvTrackInfo#TYPE_SUBTITLE}.
196410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @return the list of tracks for the given type.
19651f213914c45c23c653f721690da2ce0718e63139Dongwon Kang         */
19664bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang        @Nullable
196710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public List<TvTrackInfo> getTracks(int type) {
19686f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
19696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
19706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mAudioTracks == null) {
19716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
19726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
1973093d994965bef197fb676731fc50f6f6f630b8feJae Seo                    return new ArrayList<>(mAudioTracks);
19746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
19756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mVideoTracks == null) {
19766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
19776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
1978093d994965bef197fb676731fc50f6f6f630b8feJae Seo                    return new ArrayList<>(mVideoTracks);
19796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
19806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (mSubtitleTracks == null) {
19816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        return null;
19826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
1983093d994965bef197fb676731fc50f6f6f630b8feJae Seo                    return new ArrayList<>(mSubtitleTracks);
198410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                }
19851f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
198610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
19871f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
19881f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
1989d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo        /**
199010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * Returns the selected track for a given type. Returns {@code null} if the information is
199110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * not available or any of the tracks for the given type is not selected.
199210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         *
1993a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * @return The ID of the selected track.
199410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo         * @see #selectTrack
1995d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo         */
19964bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang        @Nullable
199710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public String getSelectedTrack(int type) {
19986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
19996320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO) {
20006320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedAudioTrackId;
20016320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO) {
20026320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedVideoTrackId;
20036320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE) {
20046320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return mSelectedSubtitleTrackId;
20056320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
2006d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
200710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            throw new IllegalArgumentException("invalid type: " + type);
20081f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
20091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
20101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        /**
20116320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTracksChanged() and updates the internal track information. Returns true if
20126320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * there is an update.
20136320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
20146320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTracks(List<TvTrackInfo> tracks) {
20156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
20166320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mAudioTracks.clear();
20176320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mVideoTracks.clear();
20186320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                mSubtitleTracks.clear();
20196320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                for (TvTrackInfo track : tracks) {
20206320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    if (track.getType() == TvTrackInfo.TYPE_AUDIO) {
20216320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mAudioTracks.add(track);
20226320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_VIDEO) {
20236320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mVideoTracks.add(track);
20246320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    } else if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) {
20256320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        mSubtitleTracks.add(track);
20266320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
20276320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
20286320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                return !mAudioTracks.isEmpty() || !mVideoTracks.isEmpty()
20296320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        || !mSubtitleTracks.isEmpty();
20306320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
20316320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
20326320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
20336320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
20346320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Responds to onTrackSelected() and updates the internal track selection information.
20356320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns true if there is an update.
20366320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
20376320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        boolean updateTrackSelection(int type, String trackId) {
20386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
2039777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seo                if (type == TvTrackInfo.TYPE_AUDIO
2040777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seo                        && !TextUtils.equals(trackId, mSelectedAudioTrackId)) {
20416320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedAudioTrackId = trackId;
20426320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
2043777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seo                } else if (type == TvTrackInfo.TYPE_VIDEO
2044777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seo                        && !TextUtils.equals(trackId, mSelectedVideoTrackId)) {
20456320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedVideoTrackId = trackId;
20466320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
20476320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                } else if (type == TvTrackInfo.TYPE_SUBTITLE
2048777718220cdacb82e984c7ea8915e36ea203e5a2Jae Seo                        && !TextUtils.equals(trackId, mSelectedSubtitleTrackId)) {
20496320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    mSelectedSubtitleTrackId = trackId;
20506320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    return true;
20516320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
20526320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
20536320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return false;
20546320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
20556320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
20566320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
20576320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * Returns the new/updated video track that contains new video size information. Returns
20586320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * null if there is no video track to notify. Subsequent calls of this method results in a
20596320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * non-null video track returned only by the first call and null returned by following
20606320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * calls. The caller should immediately notify of the video size change upon receiving the
20616320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         * track.
20626320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo         */
20636320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        TvTrackInfo getVideoTrackToNotify() {
20646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            synchronized (mMetadataLock) {
20656320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                if (!mVideoTracks.isEmpty() && mSelectedVideoTrackId != null) {
20666320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    for (TvTrackInfo track : mVideoTracks) {
20676320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        if (track.getId().equals(mSelectedVideoTrackId)) {
20686320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoWidth = track.getVideoWidth();
20696320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            int videoHeight = track.getVideoHeight();
20706320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            if (mVideoWidth != videoWidth || mVideoHeight != videoHeight) {
20716320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoWidth = videoWidth;
20726320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                mVideoHeight = videoHeight;
20736320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                                return track;
20746320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                            }
20756320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                        }
20766320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                    }
20776320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo                }
20786320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            }
20796320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo            return null;
20806320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        }
20816320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo
20826320fc490fe73b089cdccfc617e4b09f31f5d203Jae Seo        /**
2083a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         * Plays a given recorded TV program.
2084a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
2085a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void timeShiftPlay(Uri recordedProgramUri) {
2086a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mToken == null) {
2087a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                Log.w(TAG, "The session has been already released");
2088a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                return;
2089a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2090a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            try {
2091a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mService.timeShiftPlay(mToken, recordedProgramUri, mUserId);
2092a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            } catch (RemoteException e) {
2093c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
2094a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2095a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
2096a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
2097a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
20986f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * Pauses the playback. Call {@link #timeShiftResume()} to restart the playback.
20996f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
21006f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void timeShiftPause() {
21016f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mToken == null) {
21026f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "The session has been already released");
21036f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
21046f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21056f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            try {
21066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                mService.timeShiftPause(mToken, mUserId);
21076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            } catch (RemoteException e) {
2108c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
21096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
21116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
21126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
21136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         * Resumes the playback. No-op if it is already playing the channel.
21146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
21156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void timeShiftResume() {
21166f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mToken == null) {
21176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "The session has been already released");
21186f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
21196f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            try {
21216f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                mService.timeShiftResume(mToken, mUserId);
21226f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            } catch (RemoteException e) {
2123c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
21246f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21256f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
21266f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
21276f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
2128465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * Seeks to a specified time position.
21290610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         *
21300610e12733875a267f59d87a2a68aebbf486066eDongwon Kang         * <p>Normally, the position is given within range between the start and the current time,
2131465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * inclusively.
21326f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
2133465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @param timeMs The time position to seek to, in milliseconds since the epoch.
2134465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged
21356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
21366f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        void timeShiftSeekTo(long timeMs) {
21376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mToken == null) {
21386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "The session has been already released");
21396f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
21406f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21416f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            try {
21426f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                mService.timeShiftSeekTo(mToken, timeMs, mUserId);
21436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            } catch (RemoteException e) {
2144c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
21456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
21476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
21486f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
21494b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo         * Sets playback rate using {@link android.media.PlaybackParams}.
21506f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         *
21514b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo         * @param params The playback params.
21526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
21534b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo        void timeShiftSetPlaybackParams(PlaybackParams params) {
21546f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mToken == null) {
21556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "The session has been already released");
21566f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
21576f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21586f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            try {
21594b34cc77630112d00e9a87498d05f5f8803a9ff6Jae Seo                mService.timeShiftSetPlaybackParams(mToken, params, mUserId);
21606f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            } catch (RemoteException e) {
2161c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
21626f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21636f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
21646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
21656f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
2166465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * Enable/disable position tracking.
2167465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         *
2168465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo         * @param enable {@code true} to enable tracking, {@code false} otherwise.
21696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang         */
2170465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo        void timeShiftEnablePositionTracking(boolean enable) {
21716f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            if (mToken == null) {
21726f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                Log.w(TAG, "The session has been already released");
21736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang                return;
21746f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
21756f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            try {
2176465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo                mService.timeShiftEnablePositionTracking(mToken, enable, mUserId);
21776f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            } catch (RemoteException e) {
2178c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
2179a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2180a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
2181a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
2182a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
21834eee6a73e476cd2d82a69f3a535628901047f140Jae Seo         * Starts TV program recording in the current recording session.
21844eee6a73e476cd2d82a69f3a535628901047f140Jae Seo         *
21850cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang         * @param programUri The URI for the TV program to record as a hint, built by
21864eee6a73e476cd2d82a69f3a535628901047f140Jae Seo         *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
2187a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
21880cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang        void startRecording(@Nullable Uri programUri) {
2189a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mToken == null) {
2190a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                Log.w(TAG, "The session has been already released");
2191a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                return;
2192a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2193a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            try {
21940cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang                mService.startRecording(mToken, programUri, mUserId);
2195a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            } catch (RemoteException e) {
2196c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
2197a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2198a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        }
2199a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo
2200a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        /**
22014eee6a73e476cd2d82a69f3a535628901047f140Jae Seo         * Stops TV program recording in the current recording session.
2202a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo         */
2203a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo        void stopRecording() {
2204a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            if (mToken == null) {
2205a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                Log.w(TAG, "The session has been already released");
2206a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                return;
2207a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            }
2208a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            try {
2209a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo                mService.stopRecording(mToken, mUserId);
2210a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo            } catch (RemoteException e) {
2211c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
22126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang            }
22136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        }
22146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang
22156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang        /**
22161f81b1040f40a3233981f34268b11e5c9ad9f34cDongwon Kang         * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
2217a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * TvInputService.Session.appPrivateCommand()} on the current TvView.
2218a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *
2219a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param action Name of the command to be performed. This <em>must</em> be a scoped name,
2220a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            i.e. prefixed with a package name you own, so that different developers will
2221a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         *            not create conflicting commands.
2222a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         * @param data Any data to include with the command.
2223a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo         */
2224a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(String action, Bundle data) {
2225a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            if (mToken == null) {
2226a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Log.w(TAG, "The session has been already released");
2227a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                return;
2228a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
2229a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
2230a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                mService.sendAppPrivateCommand(mToken, action, data, mUserId);
2231a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } catch (RemoteException e) {
2232c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
2233a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
2234a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
2235a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
2236a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        /**
22379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView}
22389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * should be called whenever the layout of its containing view is changed.
22399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * {@link #removeOverlayView()} should be called to remove the overlay view.
22409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Since a session can have only one overlay view, this method should be called only once
22419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * or it can be called again after calling {@link #removeOverlayView()}.
22429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
22439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param view A view playing TV.
22449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A position of the overlay view.
2245dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim         * @throws IllegalStateException if {@code view} is not attached to a window.
22469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
2247de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        void createOverlayView(@NonNull View view, @NonNull Rect frame) {
2248de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(view);
2249de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(frame);
22509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (view.getWindowToken() == null) {
22519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                throw new IllegalStateException("view must be attached to a window");
22529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
2254dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
2255dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
22569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
22589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
22599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
2260c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
22619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
22639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
22649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
22659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Relayouts the current overlay view.
22669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         *
22679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * @param frame A new position of the overlay view.
22689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
2269de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        void relayoutOverlayView(@NonNull Rect frame) {
2270de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(frame);
22719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
2272dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
2273dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
22749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
22769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.relayoutOverlayView(mToken, frame, mUserId);
22779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
2278c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
22799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
22819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
22829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        /**
22839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         * Removes the current overlay view.
22849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho         */
22859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        void removeOverlayView() {
22869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            if (mToken == null) {
2287dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                Log.w(TAG, "The session has been already released");
2288dc952584e37fca96ad0e02e13b2438038fef6befSungsoo Lim                return;
22899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
22919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                mService.removeOverlayView(mToken, mUserId);
22929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } catch (RemoteException e) {
2293c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
22949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
22959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
22966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
22976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
22989bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim         * Requests to unblock content blocked by parental controls.
2299903d6b72cd572665309633e925485464d08bb25aJaewan Kim         */
2300a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo        void unblockContent(@NonNull TvContentRating unblockedRating) {
2301de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(unblockedRating);
2302903d6b72cd572665309633e925485464d08bb25aJaewan Kim            if (mToken == null) {
2303903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Log.w(TAG, "The session has been already released");
2304903d6b72cd572665309633e925485464d08bb25aJaewan Kim                return;
2305903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
2306903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
2307a90338396c90f19b062b696cdb1ffcb8600755b2Jae Seo                mService.unblockContent(mToken, unblockedRating.flattenToString(), mUserId);
2308903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } catch (RemoteException e) {
2309c53962d4ede82a03b62f0c8bb86bd0da090a15ebJeff Sharkey                throw e.rethrowFromSystemServer();
2310903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
2311903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
2312903d6b72cd572665309633e925485464d08bb25aJaewan Kim
2313903d6b72cd572665309633e925485464d08bb25aJaewan Kim        /**
23146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Dispatches an input event to this session.
23156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
2316de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo         * @param event An {@link InputEvent} to dispatch. Cannot be {@code null}.
23176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @param token A token used to identify the input event later in the callback.
2318de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo         * @param callback A callback used to receive the dispatch result. Cannot be {@code null}.
2319de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo         * @param handler A {@link Handler} that the dispatch result will be delivered to. Cannot be
2320de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo         *            {@code null}.
23216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @return Returns {@link #DISPATCH_HANDLED} if the event was handled. Returns
23226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_NOT_HANDLED} if the event was not handled. Returns
23236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the callback will
23246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *         be invoked later.
23256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
23266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
2327de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo        public int dispatchInputEvent(@NonNull InputEvent event, Object token,
2328de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo                @NonNull FinishedInputEventCallback callback, @NonNull Handler handler) {
2329de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(event);
2330de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(callback);
2331de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo            Preconditions.checkNotNull(handler);
23326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
23336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mChannel == null) {
23346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_NOT_HANDLED;
23356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
23366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                PendingEvent p = obtainPendingEventLocked(event, token, callback, handler);
23376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (Looper.myLooper() == Looper.getMainLooper()) {
23386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    // Already running on the main thread so we can send the event immediately.
23396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return sendInputEventOnMainLooperLocked(p);
23406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
23416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the main thread.
23436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_SEND_INPUT_EVENT, p);
23446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
23456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandler.sendMessage(msg);
23466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                return DISPATCH_IN_PROGRESS;
23476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
23486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
23496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        /**
23516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * Callback that is invoked when an input event that was dispatched to this session has been
23526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * finished.
23536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         *
23546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         * @hide
23556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo         */
23566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        public interface FinishedInputEventCallback {
23576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            /**
23586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * Called when the dispatched input event is finished.
23596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *
23608e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim             * @param token A token passed to {@link #dispatchInputEvent}.
23616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             * @param handled {@code true} if the dispatched input event was handled properly.
23626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             *            {@code false} otherwise.
23636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo             */
23646e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo            void onFinishedInputEvent(Object token, boolean handled);
23656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
23666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Must be called on the main looper
23686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
23696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
23706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int result = sendInputEventOnMainLooperLocked(p);
23716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (result == DISPATCH_IN_PROGRESS) {
23726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return;
23736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
23746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
23756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23766a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, false);
23776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
23786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private int sendInputEventOnMainLooperLocked(PendingEvent p) {
23806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (mChannel != null) {
23816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender == null) {
23826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mSender = new TvInputEventSender(mChannel, mHandler.getLooper());
23836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
23846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final InputEvent event = p.mEvent;
23866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                final int seq = event.getSequenceNumber();
23876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (mSender.sendInputEvent(seq, event)) {
23886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mPendingEvents.put(seq, p);
23896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Message msg = mHandler.obtainMessage(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
23906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    msg.setAsynchronous(true);
23916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.sendMessageDelayed(msg, INPUT_SESSION_NOT_RESPONDING_TIMEOUT);
23926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return DISPATCH_IN_PROGRESS;
23936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
23946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
23956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Log.w(TAG, "Unable to send input event to session: " + mToken + " dropping:"
23966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        + event);
23976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
23986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return DISPATCH_NOT_HANDLED;
23996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void finishedInputEvent(int seq, boolean handled, boolean timeout) {
24026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final PendingEvent p;
24036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            synchronized (mHandler) {
24046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int index = mPendingEvents.indexOfKey(seq);
24056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (index < 0) {
24066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    return; // spurious, event already finished or timed out
24076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
24086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = mPendingEvents.valueAt(index);
24106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mPendingEvents.removeAt(index);
24116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                if (timeout) {
241340c5c7dcdc9f39100833e86884d86fb7643ffa4bJae Seo                    Log.w(TAG, "Timeout waiting for session to handle input event after "
24146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                            + INPUT_SESSION_NOT_RESPONDING_TIMEOUT + " ms: " + mToken);
24156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                } else {
24166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    mHandler.removeMessages(InputEventHandler.MSG_TIMEOUT_INPUT_EVENT, p);
24176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
24186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
24196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            invokeFinishedInputEventCallback(p, handled);
24216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        // Assumes the event has already been removed from the queue.
24246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
24256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mHandled = handled;
24265b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            if (p.mEventHandler.getLooper().isCurrentThread()) {
24276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Already running on the callback handler thread so we can send the callback
24286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // immediately.
24296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p.run();
24306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            } else {
24316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // Post the event to the callback handler thread.
24326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                // In this case, the callback will be responsible for recycling the event.
24335b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                Message msg = Message.obtain(p.mEventHandler, p);
24346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
24356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
24366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
24376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void flushPendingEventsLocked() {
24406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
24416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            final int count = mPendingEvents.size();
24436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            for (int i = 0; i < count; i++) {
24446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                int seq = mPendingEvents.keyAt(i);
24456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                Message msg = mHandler.obtainMessage(InputEventHandler.MSG_FLUSH_INPUT_EVENT, seq, 0);
24466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.setAsynchronous(true);
24476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                msg.sendToTarget();
24486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
24496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
24526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                FinishedInputEventCallback callback, Handler handler) {
24536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            PendingEvent p = mPendingEventPool.acquire();
24546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            if (p == null) {
24556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                p = new PendingEvent();
24566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
24576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mEvent = event;
24585b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventToken = token;
24596a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.mCallback = callback;
24605b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            p.mEventHandler = handler;
24616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            return p;
24626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private void recyclePendingEventLocked(PendingEvent p) {
24656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            p.recycle();
24666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            mPendingEventPool.release(p);
24676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
24686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
2469bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        IBinder getToken() {
2470bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            return mToken;
2471bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        }
2472bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang
24732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private void releaseInternal() {
24742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mToken = null;
24752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mHandler) {
24762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mChannel != null) {
24772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (mSender != null) {
24782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        flushPendingEventsLocked();
24792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender.dispose();
24802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mSender = null;
24812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
24822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel.dispose();
24832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    mChannel = null;
24842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
24852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
24862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mSessionCallbackRecordMap) {
24872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSessionCallbackRecordMap.remove(mSeq);
24882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
24892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
24902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
24916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class InputEventHandler extends Handler {
24926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_SEND_INPUT_EVENT = 1;
24936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
24946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public static final int MSG_FLUSH_INPUT_EVENT = 3;
24956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
24966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            InputEventHandler(Looper looper) {
24976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(looper, null, true);
24986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
24996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
25016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void handleMessage(Message msg) {
25026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                switch (msg.what) {
25036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_SEND_INPUT_EVENT: {
25046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        sendInputEventAndReportResultOnMainLooper((PendingEvent) msg.obj);
25056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
25066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
25076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_TIMEOUT_INPUT_EVENT: {
25086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, true);
25096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
25106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
25116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    case MSG_FLUSH_INPUT_EVENT: {
25126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        finishedInputEvent(msg.arg1, false, false);
25136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                        return;
25146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    }
25156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
25166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
25176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
25186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class TvInputEventSender extends InputEventSender {
25206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public TvInputEventSender(InputChannel inputChannel, Looper looper) {
25216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                super(inputChannel, looper);
25226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
25236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
25256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void onInputEventFinished(int seq, boolean handled) {
25266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                finishedInputEvent(seq, handled, false);
25276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
25286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
25296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        private final class PendingEvent implements Runnable {
25316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public InputEvent mEvent;
25325b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Object mEventToken;
25336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public FinishedInputEventCallback mCallback;
25345b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo            public Handler mEventHandler;
25356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public boolean mHandled;
25366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void recycle() {
25386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mEvent = null;
25395b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventToken = null;
25406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mCallback = null;
25415b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mEventHandler = null;
25426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                mHandled = false;
25436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
25446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            @Override
25466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            public void run() {
25475b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                mCallback.onFinishedInputEvent(mEventToken, mHandled);
25486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
25495b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo                synchronized (mEventHandler) {
25506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    recyclePendingEventLocked(this);
25516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                }
25526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo            }
25536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        }
25543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2555d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2556d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    /**
2557d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * The Hardware provides the per-hardware functionality of TV hardware.
2558d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
25590610e12733875a267f59d87a2a68aebbf486066eDongwon Kang     * <p>TV hardware is physical hardware attached to the Android device; for example, HDMI ports,
2560d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * Component/Composite ports, etc. Specifically, logical devices such as HDMI CEC logical
2561d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * devices don't fall into this category.
2562d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     *
2563d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     * @hide
2564d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim     */
2565d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    @SystemApi
2566d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    public final static class Hardware {
2567d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private final ITvInputHardware mInterface;
2568d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2569d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private Hardware(ITvInputHardware hardwareInterface) {
2570d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            mInterface = hardwareInterface;
2571d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2572d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2573d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        private ITvInputHardware getInterface() {
2574d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            return mInterface;
2575d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2576d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2577d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean setSurface(Surface surface, TvStreamConfig config) {
2578d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
2579d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.setSurface(surface, config);
2580d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
2581d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
2582d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
2583d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2584d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2585d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void setStreamVolume(float volume) {
2586d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
2587d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.setStreamVolume(volume);
2588d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
2589d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
2590d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
2591d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2592d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2593d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public boolean dispatchKeyEventToHdmi(KeyEvent event) {
2594d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
2595d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                return mInterface.dispatchKeyEventToHdmi(event);
2596d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
2597d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
2598d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
2599d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2600d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim
2601d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
2602d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                int channelMask, int format) {
2603d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            try {
2604d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                mInterface.overrideAudioSink(audioType, audioAddress, samplingRate, channelMask,
2605d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                        format);
2606d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            } catch (RemoteException e) {
2607d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim                throw new RuntimeException(e);
2608d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim            }
2609d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim        }
2610d71c691bc56ef4c5c3cf6b4cabcc450d6b1820c0Wonsik Kim    }
26113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2612