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 19cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seoimport android.annotation.FloatRange; 20a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seoimport android.annotation.MainThread; 21c8b7356434f665c494504661a943323c0bbe702eJae Seoimport android.annotation.NonNull; 224bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kangimport android.annotation.Nullable; 232c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seoimport android.annotation.SuppressLint; 24187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.annotation.SystemApi; 25345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seoimport android.app.ActivityManager; 263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.app.Service; 279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.content.Context; 283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Intent; 299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.PixelFormat; 309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect; 3161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 323d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seoimport android.media.PlaybackParams; 333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri; 34ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kangimport android.os.AsyncTask; 35832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle; 363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Handler; 373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder; 383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Message; 39ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kangimport android.os.Process; 403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteCallbackList; 413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException; 42bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kangimport android.text.TextUtils; 433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.Log; 449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.Gravity; 456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel; 466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputDevice; 476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEvent; 486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputEventReceiver; 496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.KeyEvent; 506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.MotionEvent; 513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface; 529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.View; 539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.view.WindowManager; 542c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seoimport android.view.accessibility.CaptioningManager; 55ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kangimport android.widget.FrameLayout; 563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport com.android.internal.os.SomeArgs; 58de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seoimport com.android.internal.util.Preconditions; 593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 603eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kangimport java.util.ArrayList; 6110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seoimport java.util.HashSet; 621f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport java.util.List; 6310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seoimport java.util.Set; 641f213914c45c23c653f721690da2ce0718e63139Dongwon Kang 653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** 66782f7345471072b630e58c7abd3579b0015273b1Jae Seo * The TvInputService class represents a TV input or source such as HDMI or built-in tuner which 67782f7345471072b630e58c7abd3579b0015273b1Jae Seo * provides pass-through video or broadcast TV programs. 680610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 690610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Applications will not normally use this service themselves, instead relying on the standard 70782f7345471072b630e58c7abd3579b0015273b1Jae Seo * interaction provided by {@link TvView}. Those implementing TV input services should normally do 71782f7345471072b630e58c7abd3579b0015273b1Jae Seo * so by deriving from this class and providing their own session implementation based on 72782f7345471072b630e58c7abd3579b0015273b1Jae Seo * {@link TvInputService.Session}. All TV input services must require that clients hold the 73782f7345471072b630e58c7abd3579b0015273b1Jae Seo * {@link android.Manifest.permission#BIND_TV_INPUT} in order to interact with the service; if this 74782f7345471072b630e58c7abd3579b0015273b1Jae Seo * permission is not specified in the manifest, the system will refuse to bind to that TV input 75782f7345471072b630e58c7abd3579b0015273b1Jae Seo * service. 763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic abstract class TvInputService extends Service { 78ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo private static final boolean DEBUG = false; 793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final String TAG = "TvInputService"; 803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 81e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho private static final int DETACH_OVERLAY_VIEW_TIMEOUT_MS = 5000; 82e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho 833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * This is the interface name that a service implementing a TV input should say that it support 853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * -- that is, this is the action it uses for its intent filter. To be supported, the service 863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * must also require the {@link android.Manifest.permission#BIND_TV_INPUT} permission so that 873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * other applications cannot abuse it. 883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 89d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seo public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService"; 903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 91e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee /** 92e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee * Name under which a TvInputService component publishes information about itself. 93e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee * This meta-data must reference an XML resource containing an 94e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee * <code><{@link android.R.styleable#TvInputService tv-input}></code> 95e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee * tag. 96e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee */ 97e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee public static final String SERVICE_META_DATA = "android.media.tv.input"; 98e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee 9966b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang /** 10066b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * Handler instance to handle request from TV Input Manager Service. Should be run in the main 10166b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * looper to be synchronously run with {@code Session.mHandler}. 10266b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang */ 103546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo private final Handler mServiceHandler = new ServiceHandler(); 1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks = 105093d994965bef197fb676731fc50f6f6f630b8feJae Seo new RemoteCallbackList<>(); 1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 107911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang private TvInputManager mTvInputManager; 108911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang 1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public final IBinder onBind(Intent intent) { 1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return new ITvInputService.Stub() { 1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void registerCallback(ITvInputServiceCallback cb) { 1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (cb != null) { 1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mCallbacks.register(cb); 1163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void unregisterCallback(ITvInputServiceCallback cb) { 1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (cb != null) { 1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mCallbacks.unregister(cb); 1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 127187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void createSession(InputChannel channel, ITvInputSessionCallback cb, 128187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim String inputId) { 1296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (channel == null) { 1306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo Log.w(TAG, "Creating session without input channel"); 1316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 1326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (cb == null) { 1336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return; 1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1356a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo SomeArgs args = SomeArgs.obtain(); 1366a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo args.arg1 = channel; 1376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo args.arg2 = cb; 138187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim args.arg3 = inputId; 13966b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget(); 1403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 141187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 142187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 143a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void createRecordingSession(ITvInputSessionCallback cb, String inputId) { 144a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (cb == null) { 145a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo return; 146a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 147a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo SomeArgs args = SomeArgs.obtain(); 148a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo args.arg1 = cb; 149a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo args.arg2 = inputId; 150a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_RECORDING_SESSION, args) 151a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo .sendToTarget(); 152a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 153a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 154a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Override 155187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) { 1561abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT, 157187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim hardwareInfo).sendToTarget(); 158187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 159187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 160187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @Override 1614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) { 1621abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_INPUT, 1634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee hardwareInfo).sendToTarget(); 1644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 1654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 1664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee @Override 167546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) { 1681abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_INPUT, 169546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo deviceInfo).sendToTarget(); 1704f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 1714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 1724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee @Override 173546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public void notifyHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) { 1741abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT, 175546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo deviceInfo).sendToTarget(); 176187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 1783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 181782f7345471072b630e58c7abd3579b0015273b1Jae Seo * Returns a concrete implementation of {@link Session}. 1820610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 1830610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>May return {@code null} if this TV input service fails to create a session for some 1840610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * reason. If TV input represents an external device connected to a hardware TV input, 185bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * {@link HardwareSession} should be returned. 1860610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 187187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * @param inputId The ID of the TV input associated with the session. 188187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim */ 1894bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang @Nullable 1901032f034ff4f0506872e4899b5a232057abe724bWonsik Kim public abstract Session onCreateSession(String inputId); 191187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 192187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim /** 193a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Returns a concrete implementation of {@link RecordingSession}. 194a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 195a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * <p>May return {@code null} if this TV input service fails to create a recording session for 196a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * some reason. 197a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 198a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param inputId The ID of the TV input associated with the recording session. 199a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 200a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Nullable 201533b34568280e61d885c3ea438fdb585ea2e4ba0Jae Seo public RecordingSession onCreateRecordingSession(String inputId) { 202533b34568280e61d885c3ea438fdb585ea2e4ba0Jae Seo return null; 203533b34568280e61d885c3ea438fdb585ea2e4ba0Jae Seo } 204a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 205a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 2064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * Returns a new {@link TvInputInfo} object if this service is responsible for 2074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * {@code hardwareInfo}; otherwise, return {@code null}. Override to modify default behavior of 2084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * ignoring all hardware input. 209187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * 2104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * @param hardwareInfo {@link TvInputHardwareInfo} object just added. 211187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * @hide 212187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim */ 2134bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang @Nullable 214187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @SystemApi 215187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim public TvInputInfo onHardwareAdded(TvInputHardwareInfo hardwareInfo) { 216187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim return null; 217187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 218187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 219187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim /** 220187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * Returns the input ID for {@code deviceId} if it is handled by this service; 2214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * otherwise, return {@code null}. Override to modify default behavior of ignoring all hardware 2224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * input. 223187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * 2244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * @param hardwareInfo {@link TvInputHardwareInfo} object just removed. 225187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim * @hide 226187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim */ 2274bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang @Nullable 228187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim @SystemApi 2294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee public String onHardwareRemoved(TvInputHardwareInfo hardwareInfo) { 2304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee return null; 2314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 2334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /** 2344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * Returns a new {@link TvInputInfo} object if this service is responsible for 235546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * {@code deviceInfo}; otherwise, return {@code null}. Override to modify default behavior of 236546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * ignoring all HDMI logical input device. 2374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * 238546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * @param deviceInfo {@link HdmiDeviceInfo} object just added. 2394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * @hide 2404f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee */ 2414bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang @Nullable 2424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee @SystemApi 243546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public TvInputInfo onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) { 2444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee return null; 2454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 2464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 2474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee /** 2488960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * Returns the input ID for {@code deviceInfo} if it is handled by this service; otherwise, 249546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * return {@code null}. Override to modify default behavior of ignoring all HDMI logical input 250546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * device. 2514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * 252546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo * @param deviceInfo {@link HdmiDeviceInfo} object just removed. 2534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee * @hide 2544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee */ 2554bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang @Nullable 2564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee @SystemApi 257546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo public String onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) { 258187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim return null; 259187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 260187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 261911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang private boolean isPassthroughInput(String inputId) { 262911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang if (mTvInputManager == null) { 263911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE); 264911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang } 265911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang TvInputInfo info = mTvInputManager.getTvInputInfo(inputId); 2666e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo return info != null && info.isPassthroughInput(); 267911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang } 268911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang 269187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim /** 270b8a64416e5e7cf39fd899fa600a940b0ef3c15fdJae Seo * Base class for derived classes to implement to provide a TV input session. 2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 27266b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang public abstract static class Session implements KeyEvent.Callback { 2736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang private static final int POSITION_UPDATE_INTERVAL_MS = 1000; 2746f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 2756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); 2769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private final WindowManager mWindowManager; 27766b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang final Handler mHandler; 2789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private WindowManager.LayoutParams mWindowParams; 279f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho private Surface mSurface; 280c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo private final Context mContext; 281ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang private FrameLayout mOverlayViewContainer; 2829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private View mOverlayView; 283ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang private OverlayViewCleanUpTask mOverlayViewCleanUpTask; 2849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private boolean mOverlayViewEnabled; 2859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private IBinder mWindowToken; 2869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho private Rect mOverlayFrame; 28773d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen private long mStartPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME; 28873d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen private long mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME; 289465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo private final TimeShiftPositionTrackingRunnable 290465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mTimeShiftPositionTrackingRunnable = new TimeShiftPositionTrackingRunnable(); 2913eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang 292c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo private final Object mLock = new Object(); 2933eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang // @GuardedBy("mLock") 294832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho private ITvInputSessionCallback mSessionCallback; 2953eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang // @GuardedBy("mLock") 296c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo private final List<Runnable> mPendingActions = new ArrayList<>(); 2979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 29866b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang /** 29966b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * Creates a new Session. 30066b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * 30166b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * @param context The context of the application 30266b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang */ 30366b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang public Session(Context context) { 304ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mContext = context; 30566b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 30666b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang mHandler = new Handler(context.getMainLooper()); 3079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 3096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 310ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * Enables or disables the overlay view. 311ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * 312ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * <p>By default, the overlay view is disabled. Must be called explicitly after the 313ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * session is created to enable the overlay view. 314ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * 315ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * <p>The TV input service can disable its overlay view when the size of the overlay view is 316ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * insufficient to display the whole information, such as when used in Picture-in-picture. 317ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * Override {@link #onOverlayViewSizeChanged} to get the size of the overlay view, which 318ba2a1c3b92631a65d6dd1916a9d28368e1f5f589Dongwon Kang * then can be used to determine whether to enable/disable the overlay view. 3196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 3206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param enable {@code true} if you want to enable the overlay view. {@code false} 3216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * otherwise. 3226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 3239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void setOverlayViewEnabled(final boolean enable) { 3249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mHandler.post(new Runnable() { 3259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 3269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void run() { 3279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (enable == mOverlayViewEnabled) { 3289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho return; 3299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayViewEnabled = enable; 3319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (enable) { 3329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (mWindowToken != null) { 3339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho createOverlayView(mWindowToken, mOverlayFrame); 3349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } else { 3369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho removeOverlayView(false); 3379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho }); 3409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 3419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 343832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho * Dispatches an event to the application using this session. 344832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho * 345832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho * @param eventType The type of the event. 346832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho * @param eventArgs Optional arguments of the event. 347832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho * @hide 348832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho */ 3493eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang @SystemApi 350de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo public void notifySessionEvent(@NonNull final String eventType, final Bundle eventArgs) { 351de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo Preconditions.checkNotNull(eventType); 352a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 353832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho @Override 354832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho public void run() { 355832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho try { 35691a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")"); 357711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 358711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onSessionEvent(eventType, eventArgs); 359711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 360832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } catch (RemoteException e) { 361465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in sending event (event=" + eventType + ")", e); 362832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 363832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 364832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho }); 365832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 366832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 367832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho /** 3684640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * Informs the application that the current channel is re-tuned for some reason and the 3694640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * session now displays the content from a new channel. This is used to handle special cases 3704640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * such as when the current channel becomes unavailable, it is necessary to send the user to 3714640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * a certain channel or the user changes channel in some other way (e.g. by using a 3724640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * dedicated remote). 373a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang * 3744640d3d81a182e8f3ce50199bff1d97519d27938Jae Seo * @param channelUri The URI of the new channel. 375a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang */ 37691a801d42f3acc35404da51ba26605093922503aJae Seo public void notifyChannelRetuned(final Uri channelUri) { 377a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 378a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 379a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang @Override 380a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void run() { 381a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang try { 38291a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifyChannelRetuned"); 383711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 384711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onChannelRetuned(channelUri); 385711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 386a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } catch (RemoteException e) { 387465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyChannelRetuned", e); 388a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 389a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 390a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang }); 391a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 392a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang 393a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang /** 3948ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * Sends the list of all audio/video/subtitle tracks. The is used by the framework to 3958ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * maintain the track information for a given session, which in turn is used by 3968ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * {@link TvView#getTracks} for the application to retrieve metadata for a given track type. 3978ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * The TV input service must call this method as soon as the track information becomes 3988ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * available or is updated. Note that in a case where a part of the information for a 3998ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * certain track is updated, it is not necessary to create a new {@link TvTrackInfo} object 4008ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * with a different track ID. 401b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang * 4021f213914c45c23c653f721690da2ce0718e63139Dongwon Kang * @param tracks A list which includes track information. 40310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo */ 40410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo public void notifyTracksChanged(final List<TvTrackInfo> tracks) { 4055a3ef42422ea542fce1d8d1d5b0fbf61d4a570a6Terry Heo final List<TvTrackInfo> tracksCopy = new ArrayList<>(tracks); 406a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 407a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 408b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang @Override 409b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang public void run() { 410b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang try { 41110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo if (DEBUG) Log.d(TAG, "notifyTracksChanged"); 412711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 4135a3ef42422ea542fce1d8d1d5b0fbf61d4a570a6Terry Heo mSessionCallback.onTracksChanged(tracksCopy); 414711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 415b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang } catch (RemoteException e) { 416465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyTracksChanged", e); 417b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang } 418b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang } 419b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang }); 420b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang } 421b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang 422b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang /** 4238ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * Sends the type and ID of a selected track. This is used to inform the application that a 4248ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * specific track is selected. The TV input service must call this method as soon as a track 4258ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * is selected either by default or in response to a call to {@link #onSelectTrack}. The 4268ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * selected track ID for a given type is maintained in the framework until the next call to 4278ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * this method even after the entire track list is updated (but is reset when the session is 4288ddb01ec7b1360e9fccf341b5f1989182160fceeJae Seo * tuned to a new channel), so care must be taken not to result in an obsolete track ID. 429d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo * 43010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @param type The type of the selected track. The type can be 43110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or 43210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * {@link TvTrackInfo#TYPE_SUBTITLE}. 43310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @param trackId The ID of the selected track. 43410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @see #onSelectTrack 435d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo */ 43610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo public void notifyTrackSelected(final int type, final String trackId) { 437a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 438a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 439d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo @Override 440d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo public void run() { 441d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo try { 44210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo if (DEBUG) Log.d(TAG, "notifyTrackSelected"); 443711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 444711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onTrackSelected(type, trackId); 445711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 446d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo } catch (RemoteException e) { 447465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyTrackSelected", e); 448d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo } 449d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo } 450d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo }); 451d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo } 452d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo 453d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo /** 4541bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * Informs the application that the video is now available for watching. Video is blocked 4551bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * until this method is called. 4561bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * 4571bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * <p>The TV input service must call this method as soon as the content rendered onto its 458e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * surface is ready for viewing. This method must be called each time {@link #onTune} 4591bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * is called. 460d254611778be6bcaf091f1b081caf839dedf79acJae Seo * 461d254611778be6bcaf091f1b081caf839dedf79acJae Seo * @see #notifyVideoUnavailable 4629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang */ 46391a801d42f3acc35404da51ba26605093922503aJae Seo public void notifyVideoAvailable() { 464a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 465a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 4669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang @Override 4679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang public void run() { 4689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang try { 46991a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifyVideoAvailable"); 470711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 471711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onVideoAvailable(); 472711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 4739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } catch (RemoteException e) { 474465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyVideoAvailable", e); 4759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 4769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 4779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang }); 4789b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 4799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang 4809b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang /** 481d254611778be6bcaf091f1b081caf839dedf79acJae Seo * Informs the application that the video became unavailable for some reason. This is 482d254611778be6bcaf091f1b081caf839dedf79acJae Seo * primarily used to signal the application to block the screen not to show any intermittent 483d254611778be6bcaf091f1b081caf839dedf79acJae Seo * video artifacts. 484bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo * 485d254611778be6bcaf091f1b081caf839dedf79acJae Seo * @param reason The reason why the video became unavailable: 486d254611778be6bcaf091f1b081caf839dedf79acJae Seo * <ul> 487d254611778be6bcaf091f1b081caf839dedf79acJae Seo * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN} 488d254611778be6bcaf091f1b081caf839dedf79acJae Seo * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} 489d254611778be6bcaf091f1b081caf839dedf79acJae Seo * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL} 490d254611778be6bcaf091f1b081caf839dedf79acJae Seo * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING} 491ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY} 492d254611778be6bcaf091f1b081caf839dedf79acJae Seo * </ul> 493d254611778be6bcaf091f1b081caf839dedf79acJae Seo * @see #notifyVideoAvailable 494bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo */ 4953b9be6700fd631e25559693820d03389f8de3893Jae Seo public void notifyVideoUnavailable( 4963b9be6700fd631e25559693820d03389f8de3893Jae Seo @TvInputManager.VideoUnavailableReason final int reason) { 497bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START 498bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) { 4998a151a0a2143cd962764f74a75cf4e587f6759d1Jae Seo Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason); 500bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo } 501a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 502a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 503bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo @Override 504bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo public void run() { 505bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo try { 50691a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifyVideoUnavailable"); 507711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 508711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onVideoUnavailable(reason); 509711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 510bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo } catch (RemoteException e) { 511465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyVideoUnavailable", e); 512bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo } 513bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo } 514bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo }); 515bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo } 516bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo 517bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo /** 518bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo * Informs the application that the user is allowed to watch the current program content. 5190610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 5200610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Each TV input service is required to query the system whether the user is allowed to 521783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * watch the current program before showing it to the user if the parental controls is 522783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * enabled (i.e. {@link TvInputManager#isParentalControlsEnabled 523783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * TvInputManager.isParentalControlsEnabled()} returns {@code true}). Whether the TV input 524783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * service should block the content or not is determined by invoking 525783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#isRatingBlocked TvInputManager.isRatingBlocked(TvContentRating)} 526783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * with the content rating for the current program. Then the {@link TvInputManager} makes a 527783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * judgment based on the user blocked ratings stored in the secure settings and returns the 528783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * result. If the rating in question turns out to be allowed by the user, the TV input 529783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * service must call this method to notify the application that is permitted to show the 530783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * content. 5310610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 5320610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Each TV input service also needs to continuously listen to any changes made to the 533783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * parental controls settings by registering a broadcast receiver to receive 534783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED} and 535783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} and immediately 536783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * reevaluate the current program with the new parental controls settings. 5376057102dbb746593a7d59cf377c969b62e38c664Jae Seo * 53891a801d42f3acc35404da51ba26605093922503aJae Seo * @see #notifyContentBlocked 539783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * @see TvInputManager 5406057102dbb746593a7d59cf377c969b62e38c664Jae Seo */ 54191a801d42f3acc35404da51ba26605093922503aJae Seo public void notifyContentAllowed() { 542a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 543a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 5446057102dbb746593a7d59cf377c969b62e38c664Jae Seo @Override 5456057102dbb746593a7d59cf377c969b62e38c664Jae Seo public void run() { 5466057102dbb746593a7d59cf377c969b62e38c664Jae Seo try { 54791a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifyContentAllowed"); 548711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 549711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onContentAllowed(); 550711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 5516057102dbb746593a7d59cf377c969b62e38c664Jae Seo } catch (RemoteException e) { 552465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyContentAllowed", e); 5536057102dbb746593a7d59cf377c969b62e38c664Jae Seo } 5546057102dbb746593a7d59cf377c969b62e38c664Jae Seo } 5556057102dbb746593a7d59cf377c969b62e38c664Jae Seo }); 5566057102dbb746593a7d59cf377c969b62e38c664Jae Seo } 5576057102dbb746593a7d59cf377c969b62e38c664Jae Seo 5586057102dbb746593a7d59cf377c969b62e38c664Jae Seo /** 559bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo * Informs the application that the current program content is blocked by parent controls. 5600610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 5610610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Each TV input service is required to query the system whether the user is allowed to 562783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * watch the current program before showing it to the user if the parental controls is 563783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * enabled (i.e. {@link TvInputManager#isParentalControlsEnabled 564783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * TvInputManager.isParentalControlsEnabled()} returns {@code true}). Whether the TV input 565783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * service should block the content or not is determined by invoking 566783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#isRatingBlocked TvInputManager.isRatingBlocked(TvContentRating)} 567936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * with the content rating for the current program or {@link TvContentRating#UNRATED} in 568936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * case the rating information is missing. Then the {@link TvInputManager} makes a judgment 569936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * based on the user blocked ratings stored in the secure settings and returns the result. 570936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * If the rating in question turns out to be blocked, the TV input service must immediately 571936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * block the content and call this method with the content rating of the current program to 572936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * prompt the PIN verification screen. 5730610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 5740610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Each TV input service also needs to continuously listen to any changes made to the 575783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * parental controls settings by registering a broadcast receiver to receive 576783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED} and 577783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * {@link TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} and immediately 578783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * reevaluate the current program with the new parental controls settings. 5799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang * 580936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * @param rating The content rating for the current TV program. Can be 581936c040ec445afad98ec16fc634ae6573eceefbbJae Seo * {@link TvContentRating#UNRATED}. 58291a801d42f3acc35404da51ba26605093922503aJae Seo * @see #notifyContentAllowed 583783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo * @see TvInputManager 5849b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang */ 585c8b7356434f665c494504661a943323c0bbe702eJae Seo public void notifyContentBlocked(@NonNull final TvContentRating rating) { 586de08be8f79ea40f3dffae9edff4227704a5c0a3aJae Seo Preconditions.checkNotNull(rating); 587a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 588a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 5899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang @Override 5909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang public void run() { 5919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang try { 59291a801d42f3acc35404da51ba26605093922503aJae Seo if (DEBUG) Log.d(TAG, "notifyContentBlocked"); 593711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 594711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onContentBlocked(rating.flattenToString()); 595711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 5969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } catch (RemoteException e) { 597465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyContentBlocked", e); 5989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 5999b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 6009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang }); 6019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang } 6029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang 6039b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang /** 604465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Informs the application that the time shift status is changed. 6050610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 6060610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Prior to calling this method, the application assumes the status 607465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * {@link TvInputManager#TIME_SHIFT_STATUS_UNKNOWN}. Right after the session is created, it 608465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * is important to invoke the method with the status 609465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * {@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} if the implementation does support 610465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * time shifting, or {@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED} otherwise. Failure 611465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * to notifying the current status change immediately might result in an undesirable 612465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * behavior in the application such as hiding the play controls. 6130610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 6140610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>If the status {@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} is reported, the 615465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * application assumes it can pause/resume playback, seek to a specified time position and 616465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * set playback rate and audio mode. The implementation should override 617465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * {@link #onTimeShiftPause}, {@link #onTimeShiftResume}, {@link #onTimeShiftSeekTo}, 618465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * {@link #onTimeShiftGetStartPosition}, {@link #onTimeShiftGetCurrentPosition} and 6193d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * {@link #onTimeShiftSetPlaybackParams}. 6206f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 621465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * @param status The current time shift status. Should be one of the followings. 6226f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * <ul> 623465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED} 6246f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE} 625465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} 6266f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * </ul> 6276f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 6283b9be6700fd631e25559693820d03389f8de3893Jae Seo public void notifyTimeShiftStatusChanged(@TvInputManager.TimeShiftStatus final int status) { 629a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 630a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 6316f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang @Override 6326f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void run() { 63373d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen timeShiftEnablePositionTracking( 63473d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen status == TvInputManager.TIME_SHIFT_STATUS_AVAILABLE); 6356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang try { 6366f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (DEBUG) Log.d(TAG, "notifyTimeShiftStatusChanged"); 6376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (mSessionCallback != null) { 6386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang mSessionCallback.onTimeShiftStatusChanged(status); 6396f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6406f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } catch (RemoteException e) { 641465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyTimeShiftStatusChanged", e); 6426f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6446f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang }); 6456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 647465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo private void notifyTimeShiftStartPositionChanged(final long timeMs) { 648a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 649a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 6506f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang @Override 6516f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void run() { 6526f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang try { 6536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (DEBUG) Log.d(TAG, "notifyTimeShiftStartPositionChanged"); 6546f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (mSessionCallback != null) { 6556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang mSessionCallback.onTimeShiftStartPositionChanged(timeMs); 6566f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6576f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } catch (RemoteException e) { 658465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyTimeShiftStartPositionChanged", e); 6596f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6606f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6616f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang }); 6626f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6636f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 6646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang private void notifyTimeShiftCurrentPositionChanged(final long timeMs) { 665a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 666a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 6676f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang @Override 6686f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void run() { 6696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang try { 6706f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (DEBUG) Log.d(TAG, "notifyTimeShiftCurrentPositionChanged"); 6716f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang if (mSessionCallback != null) { 6726f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang mSessionCallback.onTimeShiftCurrentPositionChanged(timeMs); 6736f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6746f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } catch (RemoteException e) { 675465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in notifyTimeShiftCurrentPositionChanged", e); 6766f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6776f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6786f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang }); 6796f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 6806f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 6816f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 682606c8a396558e9714159db4969340af170677172Jae Seo * Assigns a size and position to the surface passed in {@link #onSetSurface}. The position 683606c8a396558e9714159db4969340af170677172Jae Seo * is relative to the overlay view that sits on top of this surface. 684ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * 685ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * @param left Left position in pixels, relative to the overlay view. 686ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * @param top Top position in pixels, relative to the overlay view. 687ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * @param right Right position in pixels, relative to the overlay view. 68879d2b4c810f9359640a0aaa80e610508481cd413Dongwon Kang * @param bottom Bottom position in pixels, relative to the overlay view. 6895b1caaf7d8408bf0ce78d8d7a36f4649dda17797Jae Seo * @see #onOverlayViewSizeChanged 690ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho */ 69179d2b4c810f9359640a0aaa80e610508481cd413Dongwon Kang public void layoutSurface(final int left, final int top, final int right, 69279d2b4c810f9359640a0aaa80e610508481cd413Dongwon Kang final int bottom) { 69379d2b4c810f9359640a0aaa80e610508481cd413Dongwon Kang if (left > right || top > bottom) { 694ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho throw new IllegalArgumentException("Invalid parameter"); 695ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 696a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 697a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 698ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho @Override 699ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho public void run() { 700ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho try { 701ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho if (DEBUG) Log.d(TAG, "layoutSurface (l=" + left + ", t=" + top + ", r=" 70279d2b4c810f9359640a0aaa80e610508481cd413Dongwon Kang + right + ", b=" + bottom + ",)"); 703711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo if (mSessionCallback != null) { 704711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo mSessionCallback.onLayoutSurface(left, top, right, bottom); 705711914421896ad15ab3c944c3adc838ac67cf2a6Jae Seo } 706ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } catch (RemoteException e) { 707465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.w(TAG, "error in layoutSurface", e); 708ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 709ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 710ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho }); 711ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 712ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho 713ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho /** 7143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Called when the session is released. 7153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 7163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public abstract void onRelease(); 7173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 71915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * Sets the current session as the main session. The main session is a session whose 72015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * corresponding TV input determines the HDMI-CEC active source device. 7210610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 7220610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>TV input service that manages HDMI-CEC logical device should implement {@link 72315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * #onSetMain} to (1) select the corresponding HDMI logical device as the source device 72415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * when {@code isMain} is {@code true}, and to (2) select the internal device (= TV itself) 72515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * as the source device when {@code isMain} is {@code false} and the session is still main. 72615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * Also, if a surface is passed to a non-main session and active source is changed to 72715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * initiate the surface, the active source should be returned to the main session. 7280610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 7290610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>{@link TvView} guarantees that, when tuning involves a session transition, {@code 73015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * onSetMain(true)} for new session is called first, {@code onSetMain(false)} for old 73115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * session is called afterwards. This allows {@code onSetMain(false)} to be no-op when TV 73215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * input service knows that the next main session corresponds to another HDMI logical 73315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * device. Practically, this implies that one TV input service should handle all HDMI port 73415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * and HDMI-CEC logical devices for smooth active source transition. 7354c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee * 73615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * @param isMain If true, session should become main. 73715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * @see TvView#setMain 7384c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee * @hide 7394c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee */ 7404c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee @SystemApi 74115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee public void onSetMain(boolean isMain) { 7424c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee } 7434c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee 744c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo /** 745606c8a396558e9714159db4969340af170677172Jae Seo * Called when the application sets the surface. 7460610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 747606c8a396558e9714159db4969340af170677172Jae Seo * <p>The TV input service should render video onto the given surface. When called with 748a9b6289faaf0ad3768fb8530b199fe7a44a241abConrad Chen * {@code null}, the input service should immediately free any references to the 749606c8a396558e9714159db4969340af170677172Jae Seo * currently set surface and stop using it. 750c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo * 751606c8a396558e9714159db4969340af170677172Jae Seo * @param surface The surface to be used for video rendering. Can be {@code null}. 752606c8a396558e9714159db4969340af170677172Jae Seo * @return {@code true} if the surface was set successfully, {@code false} otherwise. 753c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo */ 7544bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang public abstract boolean onSetSurface(@Nullable Surface surface); 7553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 757606c8a396558e9714159db4969340af170677172Jae Seo * Called after any structural changes (format or size) have been made to the surface passed 758606c8a396558e9714159db4969340af170677172Jae Seo * in {@link #onSetSurface}. This method is always called at least once, after 759606c8a396558e9714159db4969340af170677172Jae Seo * {@link #onSetSurface} is called with non-null surface. 760e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho * 761606c8a396558e9714159db4969340af170677172Jae Seo * @param format The new PixelFormat of the surface. 762606c8a396558e9714159db4969340af170677172Jae Seo * @param width The new width of the surface. 763606c8a396558e9714159db4969340af170677172Jae Seo * @param height The new height of the surface. 764e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho */ 765e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho public void onSurfaceChanged(int format, int width, int height) { 766e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho } 767e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho 768e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho /** 769606c8a396558e9714159db4969340af170677172Jae Seo * Called when the size of the overlay view is changed by the application. 770606c8a396558e9714159db4969340af170677172Jae Seo * 771606c8a396558e9714159db4969340af170677172Jae Seo * <p>This is always called at least once when the session is created regardless of whether 772606c8a396558e9714159db4969340af170677172Jae Seo * the overlay view is enabled or not. The overlay view size is the same as the containing 773606c8a396558e9714159db4969340af170677172Jae Seo * {@link TvView}. Note that the size of the underlying surface can be different if the 774606c8a396558e9714159db4969340af170677172Jae Seo * surface was changed by calling {@link #layoutSurface}. 775ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * 776ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * @param width The width of the overlay view. 777ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho * @param height The height of the overlay view. 778ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho */ 779ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho public void onOverlayViewSizeChanged(int width, int height) { 780ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 781ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho 782ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho /** 7831da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * Sets the relative stream volume of the current TV input session. 7843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * 7851da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * <p>The implementation should honor this request in order to handle audio focus changes or 7861da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * mute the current session when multiple sessions, possibly from different inputs are 7871da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * active. If the method has not yet been called, the implementation should assume the 7881da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * default value of {@code 1.0f}. 7891da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * 7901da8fb39499e8f5a962f7307fefdfd2ab6b79224Jae Seo * @param volume A volume value between {@code 0.0f} to {@code 1.0f}. 7913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 792cdfbc488c675a9800dfc8f15aec24b65a7558d29Jae Seo public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume); 7933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 7951bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * Tunes to a given channel. 7961bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * 7971bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * <p>No video will be displayed until {@link #notifyVideoAvailable()} is called. 7981bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * Also, {@link #notifyVideoUnavailable(int)} should be called when the TV input cannot 7991bccd280f59b86d00c04dcc9d827d76b373c600aNick Chalko * continue playing the given channel. 8003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * 8013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * @param channelUri The URI of the channel. 802c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo * @return {@code true} if the tuning was successful, {@code false} otherwise. 8033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 8043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public abstract boolean onTune(Uri channelUri); 8053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 807031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * Tunes to a given channel. Override this method in order to handle domain-specific 808e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * features that are only known between certain TV inputs and their clients. 8091a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim * 810031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * <p>The default implementation calls {@link #onTune(Uri)}. 811031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * 8121a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim * @param channelUri The URI of the channel. 813e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped 814e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * name, i.e. prefixed with a package name you own, so that different developers 815e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * will not create conflicting keys. 816c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo * @return {@code true} if the tuning was successful, {@code false} otherwise. 8171a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim */ 8181a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim public boolean onTune(Uri channelUri, Bundle params) { 8191a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim return onTune(channelUri); 8201a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim } 8211a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim 8221a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim /** 8232c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * Enables or disables the caption. 8240610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 8250610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>The locale for the user's preferred captioning language can be obtained by calling 8262c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * {@link CaptioningManager#getLocale CaptioningManager.getLocale()}. 8272c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * 8282c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * @param enabled {@code true} to enable, {@code false} to disable. 8292c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * @see CaptioningManager 8302c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo */ 8312c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo public abstract void onSetCaptionEnabled(boolean enabled); 8322c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo 8332c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo /** 8349bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim * Requests to unblock the content according to the given rating. 8350610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 8360610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>The implementation should unblock the content. 837903d6b72cd572665309633e925485464d08bb25aJaewan Kim * TV input service has responsibility to decide when/how the unblock expires 838903d6b72cd572665309633e925485464d08bb25aJaewan Kim * while it can keep previously unblocked ratings in order not to ask a user 839903d6b72cd572665309633e925485464d08bb25aJaewan Kim * to unblock whenever a content rating is changed. 840903d6b72cd572665309633e925485464d08bb25aJaewan Kim * Therefore an unblocked rating can be valid for a channel, a program, 841903d6b72cd572665309633e925485464d08bb25aJaewan Kim * or certain amount of time depending on the implementation. 842903d6b72cd572665309633e925485464d08bb25aJaewan Kim * 843903d6b72cd572665309633e925485464d08bb25aJaewan Kim * @param unblockedRating An unblocked content rating 844903d6b72cd572665309633e925485464d08bb25aJaewan Kim */ 84591a801d42f3acc35404da51ba26605093922503aJae Seo public void onUnblockContent(TvContentRating unblockedRating) { 8469bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim } 847903d6b72cd572665309633e925485464d08bb25aJaewan Kim 848903d6b72cd572665309633e925485464d08bb25aJaewan Kim /** 849c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo * Selects a given track. 8500610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 8510610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>If this is done successfully, the implementation should call 8520610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * {@link #notifyTrackSelected} to help applications maintain the up-to-date list of the 8530610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * selected tracks. 8542c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * 85510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @param trackId The ID of the track to select. {@code null} means to unselect the current 85610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * track for a given type. 85710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @param type The type of the track to select. The type can be 85810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or 85910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * {@link TvTrackInfo#TYPE_SUBTITLE}. 860c6a1e5d16c9e1fab5e597f308c3886e512791289Jae Seo * @return {@code true} if the track selection was successful, {@code false} otherwise. 86110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo * @see #notifyTrackSelected 86210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo */ 8634bf607b00c14c031e991ac9dc0ad49b9249c9162Dongwon Kang public boolean onSelectTrack(int type, @Nullable String trackId) { 8641f213914c45c23c653f721690da2ce0718e63139Dongwon Kang return false; 8651f213914c45c23c653f721690da2ce0718e63139Dongwon Kang } 8661f213914c45c23c653f721690da2ce0718e63139Dongwon Kang 8671f213914c45c23c653f721690da2ce0718e63139Dongwon Kang /** 868a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * Processes a private command sent from the application to the TV input. This can be used 869a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * to provide domain-specific features that are only known between certain TV inputs and 870a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * their clients. 871a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * 872a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * @param action Name of the command to be performed. This <em>must</em> be a scoped name, 873a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * i.e. prefixed with a package name you own, so that different developers will 874a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * not create conflicting commands. 875a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * @param data Any data to include with the command. 876a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo */ 877c8b7356434f665c494504661a943323c0bbe702eJae Seo public void onAppPrivateCommand(@NonNull String action, Bundle data) { 878a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo } 879a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo 880a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo /** 881465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Called when the application requests to create an overlay view. Each session 8829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * implementation can override this method and return its own view. 8839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * 8849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * @return a view attached to the overlay window 8859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */ 8869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public View onCreateOverlayView() { 8879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho return null; 8889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 8909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho /** 891a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Called when the application requests to play a given recorded TV program. 892a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 893a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param recordedProgramUri The URI of a recorded TV program. 894a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 895a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 896a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 897a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 898a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 899a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 900a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 901a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void onTimeShiftPlay(Uri recordedProgramUri) { 902a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 903a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 904a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 905465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Called when the application requests to pause playback. 9066f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 907a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 908a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 909a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 910a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 911a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 912a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 9136f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 9146f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void onTimeShiftPause() { 9156f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 9166f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 9176f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 918465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Called when the application requests to resume playback. 9196f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 920a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 921a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 922a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 923a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 924a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 925a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 9266f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 9276f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void onTimeShiftResume() { 9286f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 9296f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 9306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 931465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Called when the application requests to seek to a specified time position. Normally, the 932465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * position is given within range between the start and the current time, inclusively. The 933465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * implementation is expected to seek to the nearest time position if the given position is 934465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * not in the range. 9356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 936465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * @param timeMs The time position to seek to, in milliseconds since the epoch. 937a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 938a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 939a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 940a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 941a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 942a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 9436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 9446f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void onTimeShiftSeekTo(long timeMs) { 9456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 9466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 9476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 9483d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * Called when the application sets playback parameters containing the speed and audio mode. 9490610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 9503d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * <p>Once the playback parameters are set, the implementation should honor the current 9513d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * settings until the next tune request. Pause/resume/seek request does not reset the 9523d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * parameters previously set. 9536f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 9543d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * @param params The playback params. 955a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 956a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 957a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 958a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 959a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 960a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 9616f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 9623d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo public void onTimeShiftSetPlaybackParams(PlaybackParams params) { 9636f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 9646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 9656f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 9664e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * Returns the start position for time shifting, in milliseconds since the epoch. 967465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the 968465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * moment. 9690610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 9704e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * <p>The start position for time shifting indicates the earliest possible time the user can 9714e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * seek to. Initially this is equivalent to the time when the implementation starts 9724e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * recording. Later it may be adjusted because there is insufficient space or the duration 9734e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * of recording is limited by the implementation. The application does not allow the user to 9744e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * seek to a position earlier than the start position. 9754e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * 9764e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * <p>For playback of a recorded program initiated by {@link #onTimeShiftPlay(Uri)}, the 9774e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * start position is the time when playback starts. It does not change. 978465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * 979a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 980a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 981a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 982a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 983a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 984a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetCurrentPosition() 985465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo */ 986465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo public long onTimeShiftGetStartPosition() { 987465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo return TvInputManager.TIME_SHIFT_INVALID_TIME; 988465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo } 989465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo 990465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo /** 9914e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * Returns the current position for time shifting, in milliseconds since the epoch. 992465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the 993465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * moment. 9946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * 9954e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * <p>The current position for time shifting is the same as the current position of 9964e3ded556100f674ccba0d0e40adcbd0d30f9b23Jae Seo * playback. It should be equal to or greater than the start position reported by 9974a6d31a8f328be6163051f3d5d2da16ff551d128Conrad Chen * {@link #onTimeShiftGetStartPosition()}. When playback is completed, the current position 9984a6d31a8f328be6163051f3d5d2da16ff551d128Conrad Chen * should stay where the playback ends, in other words, the returned value of this mehtod 9994a6d31a8f328be6163051f3d5d2da16ff551d128Conrad Chen * should be equal to the start position plus the duration of the program. 1000bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang * 1001a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPlay(Uri) 1002a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftResume() 1003a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftPause() 1004a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSeekTo(long) 1005a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftSetPlaybackParams(PlaybackParams) 1006a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @see #onTimeShiftGetStartPosition() 10076f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 10086f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public long onTimeShiftGetCurrentPosition() { 10096f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang return TvInputManager.TIME_SHIFT_INVALID_TIME; 10106f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 10116f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 10126f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 10136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent) 10146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event). 10150610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 10160610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Override this to intercept key down events before they are processed by the 10170610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * application. If you return true, the application will not process the event itself. If 10180610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * you return false, the normal application processing will occur as if the TV input had not 10190610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * seen the event at all. 10206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 10216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param keyCode The value in event.getKeyCode(). 10226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event Description of the key event. 10236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 10246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 10256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 10266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo @Override 10276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onKeyDown(int keyCode, KeyEvent event) { 10286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 10296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 10306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 10316a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 10326a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Default implementation of 10336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * {@link android.view.KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 10346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle the event). 10350610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 10360610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Override this to intercept key long press events before they are processed by the 10376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * application. If you return true, the application will not process the event itself. If 10386a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * you return false, the normal application processing will occur as if the TV input had not 10396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * seen the event at all. 10406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 10416a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param keyCode The value in event.getKeyCode(). 10426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event Description of the key event. 10436a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 10446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 10456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 10466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo @Override 10476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onKeyLongPress(int keyCode, KeyEvent event) { 10486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 10496a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 10506a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 10516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 10526a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Default implementation of 10536a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * {@link android.view.KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 10546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle the event). 10550610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 10560610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Override this to intercept special key multiple events before they are processed by 10570610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * the application. If you return true, the application will not itself process the event. 10580610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * If you return false, the normal application processing will occur as if the TV input had 10590610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * not seen the event at all. 10606a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 10616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param keyCode The value in event.getKeyCode(). 10626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param count The number of times the action was made. 10636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event Description of the key event. 10646a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 10656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 10666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 10676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo @Override 10686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 10696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 10706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 10716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 10726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 10736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Default implementation of {@link android.view.KeyEvent.Callback#onKeyUp(int, KeyEvent) 10746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * KeyEvent.Callback.onKeyUp()}: always returns false (doesn't handle the event). 10750610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 10760610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Override this to intercept key up events before they are processed by the application. 10770610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * If you return true, the application will not itself process the event. If you return false, 10786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * the normal application processing will occur as if the TV input had not seen the event at 10796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * all. 10806a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 10816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param keyCode The value in event.getKeyCode(). 10826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event Description of the key event. 10836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 10846a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 10856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 10866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo @Override 10876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onKeyUp(int keyCode, KeyEvent event) { 10886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 10896a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 10906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 10916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 10926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Implement this method to handle touch screen motion events on the current input session. 10936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 10946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event The motion event being received. 10956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 10966a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 10976a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @see View#onTouchEvent 10986a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 10996a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onTouchEvent(MotionEvent event) { 11006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 11016a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 11026a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 11036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 11046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Implement this method to handle trackball events on the current input session. 11056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 11066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event The motion event being received. 11076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 11086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 11096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @see View#onTrackballEvent 11106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 11116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onTrackballEvent(MotionEvent event) { 11126a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 11136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 11146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 11156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 11166a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Implement this method to handle generic motion events on the current input session. 11176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * 11186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @param event The motion event being received. 11196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @return If you handled the event, return {@code true}. If you want to allow the event to 11206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * be handled by the next receiver, return {@code false}. 11216a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * @see View#onGenericMotionEvent 11226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 11236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo public boolean onGenericMotionEvent(MotionEvent event) { 11246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo return false; 11256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 11266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 11276a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 11283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * This method is called when the application would like to stop using the current input 11293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * session. 11303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 1131674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho void release() { 1132674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho onRelease(); 1133f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho if (mSurface != null) { 1134f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho mSurface.release(); 1135f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho mSurface = null; 1136f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho } 11373eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang synchronized(mLock) { 11383eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mSessionCallback = null; 11393eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mPendingActions.clear(); 11403eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 1141ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // Removes the overlay view lastly so that any hanging on the main thread can be handled 1142ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // in {@link #scheduleOverlayViewCleanup}. 1143ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang removeOverlayView(true); 1144465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable); 11453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 114815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee * Calls {@link #onSetMain}. 11494c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee */ 115015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee void setMain(boolean isMain) { 115115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee onSetMain(isMain); 11524c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee } 11534c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee 11544c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee /** 11556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Calls {@link #onSetSurface}. 11563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 1157674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho void setSurface(Surface surface) { 1158674e96216d6a60f0d87d3a6a0d62f358a101532bYoungsang Cho onSetSurface(surface); 1159f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho if (mSurface != null) { 1160f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho mSurface.release(); 1161f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho } 1162f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho mSurface = surface; 11633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // TODO: Handle failure. 11643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 1167e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho * Calls {@link #onSurfaceChanged}. 1168e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho */ 1169e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho void dispatchSurfaceChanged(int format, int width, int height) { 1170e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho if (DEBUG) { 1171e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho Log.d(TAG, "dispatchSurfaceChanged(format=" + format + ", width=" + width 1172e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho + ", height=" + height + ")"); 1173e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho } 1174e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho onSurfaceChanged(format, width, height); 1175e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho } 1176e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho 1177e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho /** 1178782f7345471072b630e58c7abd3579b0015273b1Jae Seo * Calls {@link #onSetStreamVolume}. 11793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 11804b662d1b98e312792235c6718afd7c406270d1f1Dongwon Kang void setStreamVolume(float volume) { 1181782f7345471072b630e58c7abd3579b0015273b1Jae Seo onSetStreamVolume(volume); 11823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo /** 1185e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * Calls {@link #onTune(Uri, Bundle)}. 11863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */ 11871a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim void tune(Uri channelUri, Bundle params) { 11886f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME; 11891a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim onTune(channelUri, params); 11903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // TODO: Handle failure. 11913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 11939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho /** 11942c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo * Calls {@link #onSetCaptionEnabled}. 11952c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo */ 11962c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo void setCaptionEnabled(boolean enabled) { 11972c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo onSetCaptionEnabled(enabled); 11982c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo } 11992c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo 12002c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo /** 12011f213914c45c23c653f721690da2ce0718e63139Dongwon Kang * Calls {@link #onSelectTrack}. 12021f213914c45c23c653f721690da2ce0718e63139Dongwon Kang */ 120310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo void selectTrack(int type, String trackId) { 120410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo onSelectTrack(type, trackId); 12051f213914c45c23c653f721690da2ce0718e63139Dongwon Kang } 12061f213914c45c23c653f721690da2ce0718e63139Dongwon Kang 12071f213914c45c23c653f721690da2ce0718e63139Dongwon Kang /** 120891a801d42f3acc35404da51ba26605093922503aJae Seo * Calls {@link #onUnblockContent}. 1209903d6b72cd572665309633e925485464d08bb25aJaewan Kim */ 121091a801d42f3acc35404da51ba26605093922503aJae Seo void unblockContent(String unblockedRating) { 121191a801d42f3acc35404da51ba26605093922503aJae Seo onUnblockContent(TvContentRating.unflattenFromString(unblockedRating)); 1212903d6b72cd572665309633e925485464d08bb25aJaewan Kim // TODO: Handle failure. 1213903d6b72cd572665309633e925485464d08bb25aJaewan Kim } 1214903d6b72cd572665309633e925485464d08bb25aJaewan Kim 1215903d6b72cd572665309633e925485464d08bb25aJaewan Kim /** 1216a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo * Calls {@link #onAppPrivateCommand}. 1217a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo */ 1218a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo void appPrivateCommand(String action, Bundle data) { 1219a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo onAppPrivateCommand(action, data); 1220a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo } 1221a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo 1222a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo /** 12236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach 12246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * to the overlay window. 12259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * 1226465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * @param windowToken A window token of the application. 12279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * @param frame A position of the overlay view. 12289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */ 12299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho void createOverlayView(IBinder windowToken, Rect frame) { 1230ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (mOverlayViewContainer != null) { 1231ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang removeOverlayView(false); 12329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 1233832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) Log.d(TAG, "create overlay view(" + frame + ")"); 12349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowToken = windowToken; 12359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayFrame = frame; 1236ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho onOverlayViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top); 12379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (!mOverlayViewEnabled) { 12389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho return; 12399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 12409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayView = onCreateOverlayView(); 12419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (mOverlayView == null) { 12429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho return; 12439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 1244ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (mOverlayViewCleanUpTask != null) { 1245ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewCleanUpTask.cancel(true); 1246ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewCleanUpTask = null; 1247ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang } 1248ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // Creates a container view to check hanging on the overlay view detaching. 1249ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // Adding/removing the overlay view to/from the container make the view attach/detach 1250ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // logic run on the main thread. 1251e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho mOverlayViewContainer = new FrameLayout(mContext.getApplicationContext()); 1252ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer.addView(mOverlayView); 12539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho // TvView's window type is TYPE_APPLICATION_MEDIA and we want to create 12549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho // an overlay window above the media window but below the application window. 12559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 12569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho // We make the overlay view non-focusable and non-touchable so that 12579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho // the application that owns the window token can decide whether to consume or 12589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho // dispatch the input events. 1259345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1260345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 1261345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 1262345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo if (ActivityManager.isHighEndGfx()) { 1263345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 1264345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo } 12659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams = new WindowManager.LayoutParams( 12669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho frame.right - frame.left, frame.bottom - frame.top, 1267345af96677d5fbfc00f8f38a46ab7d57c1ff4cbbJae Seo frame.left, frame.top, type, flags, PixelFormat.TRANSPARENT); 12689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.privateFlags |= 12699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; 12709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.gravity = Gravity.START | Gravity.TOP; 12719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.token = windowToken; 1272ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mWindowManager.addView(mOverlayViewContainer, mWindowParams); 12739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 12749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 12759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho /** 12769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * Relayouts the current overlay view. 12779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * 12789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * @param frame A new position of the overlay view. 12799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */ 12809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho void relayoutOverlayView(Rect frame) { 1281832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) Log.d(TAG, "relayoutOverlayView(" + frame + ")"); 1282ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho if (mOverlayFrame == null || mOverlayFrame.width() != frame.width() 1283ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho || mOverlayFrame.height() != frame.height()) { 1284ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho // Note: relayoutOverlayView is called whenever TvView's layout is changed 1285ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho // regardless of setOverlayViewEnabled. 1286ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho onOverlayViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top); 1287ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho } 12889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayFrame = frame; 1289ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (!mOverlayViewEnabled || mOverlayViewContainer == null) { 12909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho return; 12919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 12929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.x = frame.left; 12939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.y = frame.top; 12949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.width = frame.right - frame.left; 12959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams.height = frame.bottom - frame.top; 1296ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mWindowManager.updateViewLayout(mOverlayViewContainer, mWindowParams); 12979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 12989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 12999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho /** 13009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho * Removes the current overlay view. 13019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho */ 13029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho void removeOverlayView(boolean clearWindowToken) { 1303ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (DEBUG) Log.d(TAG, "removeOverlayView(" + mOverlayViewContainer + ")"); 13049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (clearWindowToken) { 13059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowToken = null; 13069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayFrame = null; 13079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 1308ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (mOverlayViewContainer != null) { 1309ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // Removes the overlay view from the view hierarchy in advance so that it can be 1310ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // cleaned up in the {@link OverlayViewCleanUpTask} if the remove process is 1311ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang // hanging. 1312ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer.removeView(mOverlayView); 13139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mOverlayView = null; 1314ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mWindowManager.removeView(mOverlayViewContainer); 1315ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer = null; 13169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho mWindowParams = null; 13179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 13189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 13196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 13206a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo /** 1321a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Calls {@link #onTimeShiftPlay(Uri)}. 1322a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1323a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo void timeShiftPlay(Uri recordedProgramUri) { 1324a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mCurrentPositionMs = 0; 1325a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo onTimeShiftPlay(recordedProgramUri); 1326a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1327a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1328a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 13296f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * Calls {@link #onTimeShiftPause}. 13306f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 13316f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang void timeShiftPause() { 13326f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang onTimeShiftPause(); 13336f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13346f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 13356f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 13366f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * Calls {@link #onTimeShiftResume}. 13376f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 13386f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang void timeShiftResume() { 13396f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang onTimeShiftResume(); 13406f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13416f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 13426f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 13436f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang * Calls {@link #onTimeShiftSeekTo}. 13446f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 13456f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang void timeShiftSeekTo(long timeMs) { 13466f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang onTimeShiftSeekTo(timeMs); 13476f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13486f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 13496f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 13503d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo * Calls {@link #onTimeShiftSetPlaybackParams}. 13516f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 13523d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo void timeShiftSetPlaybackParams(PlaybackParams params) { 13533d04b7693428dd887c93e2ac7f4e90fd0cc87859Jae Seo onTimeShiftSetPlaybackParams(params); 13546f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13556f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 13566f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 1357465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * Enable/disable position tracking. 1358465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * 1359465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo * @param enable {@code true} to enable tracking, {@code false} otherwise. 13606f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang */ 1361465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo void timeShiftEnablePositionTracking(boolean enable) { 1362465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo if (enable) { 1363465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mHandler.post(mTimeShiftPositionTrackingRunnable); 13646f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } else { 1365465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable); 1366465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mStartPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME; 13676f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME; 13686f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 13706f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 13716f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang /** 1372ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang * Schedules a task which checks whether the overlay view is detached and kills the process 1373ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang * if it is not. Note that this method is expected to be called in a non-main thread. 1374ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang */ 1375ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang void scheduleOverlayViewCleanup() { 1376ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang View overlayViewParent = mOverlayViewContainer; 1377ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (overlayViewParent != null) { 1378ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewCleanUpTask = new OverlayViewCleanUpTask(); 1379ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewCleanUpTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 1380ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang overlayViewParent); 1381ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang } 1382ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang } 1383ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang 1384ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang /** 13856a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo * Takes care of dispatching incoming input events and tells whether the event was handled. 13866a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo */ 13876a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { 13886a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")"); 138944fbbca35459ee756a531661eba53ec33419790aYoungsang Cho boolean isNavigationKey = false; 139053aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho boolean skipDispatchToOverlayView = false; 13916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (event instanceof KeyEvent) { 139244fbbca35459ee756a531661eba53ec33419790aYoungsang Cho KeyEvent keyEvent = (KeyEvent) event; 139344fbbca35459ee756a531661eba53ec33419790aYoungsang Cho if (keyEvent.dispatch(this, mDispatcherState, this)) { 1394782f7345471072b630e58c7abd3579b0015273b1Jae Seo return TvInputManager.Session.DISPATCH_HANDLED; 13956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 139653aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho isNavigationKey = isNavigationKey(keyEvent.getKeyCode()); 139753aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho // When media keys and KEYCODE_MEDIA_AUDIO_TRACK are dispatched to ViewRootImpl, 1398465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo // ViewRootImpl always consumes the keys. In this case, the application loses 139953aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho // a chance to handle media keys. Therefore, media keys are not dispatched to 140053aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho // ViewRootImpl. 140153aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho skipDispatchToOverlayView = KeyEvent.isMediaKey(keyEvent.getKeyCode()) 140253aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK; 14036a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } else if (event instanceof MotionEvent) { 14046a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo MotionEvent motionEvent = (MotionEvent) event; 14056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo final int source = motionEvent.getSource(); 14066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (motionEvent.isTouchEvent()) { 14076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (onTouchEvent(motionEvent)) { 1408782f7345471072b630e58c7abd3579b0015273b1Jae Seo return TvInputManager.Session.DISPATCH_HANDLED; 14096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 14106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { 14116a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (onTrackballEvent(motionEvent)) { 1412782f7345471072b630e58c7abd3579b0015273b1Jae Seo return TvInputManager.Session.DISPATCH_HANDLED; 14136a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 14146a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } else { 14156a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo if (onGenericMotionEvent(motionEvent)) { 1416782f7345471072b630e58c7abd3579b0015273b1Jae Seo return TvInputManager.Session.DISPATCH_HANDLED; 14176a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 14186a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 14196a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 142053aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho if (mOverlayViewContainer == null || !mOverlayViewContainer.isAttachedToWindow() 142153aa5744c9a233e54b8f8b8389a86f99abcc4244Youngsang Cho || skipDispatchToOverlayView) { 1422782f7345471072b630e58c7abd3579b0015273b1Jae Seo return TvInputManager.Session.DISPATCH_NOT_HANDLED; 14236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 1424ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (!mOverlayViewContainer.hasWindowFocus()) { 1425ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer.getViewRootImpl().windowFocusChanged(true, true); 14266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 1427ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang if (isNavigationKey && mOverlayViewContainer.hasFocusable()) { 142844fbbca35459ee756a531661eba53ec33419790aYoungsang Cho // If mOverlayView has focusable views, navigation key events should be always 142944fbbca35459ee756a531661eba53ec33419790aYoungsang Cho // handled. If not, it can make the application UI navigation messed up. 143044fbbca35459ee756a531661eba53ec33419790aYoungsang Cho // For example, in the case that the left-most view is focused, a left key event 143144fbbca35459ee756a531661eba53ec33419790aYoungsang Cho // will not be handled in ViewRootImpl. Then, the left key event will be handled in 143244fbbca35459ee756a531661eba53ec33419790aYoungsang Cho // the application during the UI navigation of the TV input. 1433ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer.getViewRootImpl().dispatchInputEvent(event); 143444fbbca35459ee756a531661eba53ec33419790aYoungsang Cho return TvInputManager.Session.DISPATCH_HANDLED; 143544fbbca35459ee756a531661eba53ec33419790aYoungsang Cho } else { 1436ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang mOverlayViewContainer.getViewRootImpl().dispatchInputEvent(event, receiver); 143744fbbca35459ee756a531661eba53ec33419790aYoungsang Cho return TvInputManager.Session.DISPATCH_IN_PROGRESS; 143844fbbca35459ee756a531661eba53ec33419790aYoungsang Cho } 14396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo } 1440832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 14413eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang private void initialize(ITvInputSessionCallback callback) { 14423eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang synchronized(mLock) { 14433eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mSessionCallback = callback; 14443eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang for (Runnable runnable : mPendingActions) { 14453eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang runnable.run(); 14463eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 14473eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mPendingActions.clear(); 14483eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 1449832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 14509044be13dc0b625f10c459574abdd22603f86d50Youngsang Cho 1451a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private void executeOrPostRunnableOnMainThread(Runnable action) { 14523eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang synchronized(mLock) { 14533eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang if (mSessionCallback == null) { 14543eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang // The session is not initialized yet. 14553eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mPendingActions.add(action); 14563eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } else { 14573eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang if (mHandler.getLooper().isCurrentThread()) { 14583eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang action.run(); 14593eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } else { 14603eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang // Posts the runnable if this is not called from the main thread 14613eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang mHandler.post(action); 14623eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 14633eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 14649044be13dc0b625f10c459574abdd22603f86d50Youngsang Cho } 14659044be13dc0b625f10c459574abdd22603f86d50Youngsang Cho } 1466ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang 1467465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo private final class TimeShiftPositionTrackingRunnable implements Runnable { 14686f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang @Override 14696f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang public void run() { 1470465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo long startPositionMs = onTimeShiftGetStartPosition(); 147173d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen if (mStartPositionMs == TvInputManager.TIME_SHIFT_INVALID_TIME 147273d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen || mStartPositionMs != startPositionMs) { 1473465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mStartPositionMs = startPositionMs; 1474465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo notifyTimeShiftStartPositionChanged(startPositionMs); 1475465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo } 1476465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo long currentPositionMs = onTimeShiftGetCurrentPosition(); 1477bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang if (currentPositionMs < mStartPositionMs) { 1478bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang Log.w(TAG, "Current position (" + currentPositionMs + ") cannot be earlier than" 1479bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang + " start position (" + mStartPositionMs + "). Reset to the start " 1480bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang + "position."); 1481bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang currentPositionMs = mStartPositionMs; 1482bb3e2674b5ad095d9c1e5e6069cd6b8ee1c1c11eDongwon Kang } 148373d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen if (mCurrentPositionMs == TvInputManager.TIME_SHIFT_INVALID_TIME 148473d86e34bb2ce73c88f1a3496b71fe34113d1296Conrad Chen || mCurrentPositionMs != currentPositionMs) { 1485465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mCurrentPositionMs = currentPositionMs; 1486465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo notifyTimeShiftCurrentPositionChanged(currentPositionMs); 14876f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 1488465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable); 1489465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo mHandler.postDelayed(mTimeShiftPositionTrackingRunnable, 14906f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang POSITION_UPDATE_INTERVAL_MS); 14916f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 14926f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang } 1493e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho } 14946f0240cf63fe62b0af2c7d5112f9881d1e167bfcDongwon Kang 1495e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho private static final class OverlayViewCleanUpTask extends AsyncTask<View, Void, Void> { 1496e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho @Override 1497e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho protected Void doInBackground(View... views) { 1498e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho View overlayViewParent = views[0]; 1499e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho try { 1500e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho Thread.sleep(DETACH_OVERLAY_VIEW_TIMEOUT_MS); 1501e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho } catch (InterruptedException e) { 1502e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho return null; 1503e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho } 1504e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho if (isCancelled()) { 1505ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang return null; 1506ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang } 1507e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho if (overlayViewParent.isAttachedToWindow()) { 1508e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho Log.e(TAG, "Time out on releasing overlay view. Killing " 1509e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho + overlayViewParent.getContext().getPackageName()); 1510e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho Process.killProcess(Process.myPid()); 1511e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho } 1512e2cd56cc8aeaa317f31fd7732587d1a22ef1f3d5Youngsang Cho return null; 1513ce34c6d308629c214ab9b7963755eb60cac03c9dDongwon Kang } 15143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 15153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1516bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang /** 1517a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Base class for derived classes to implement to provide a TV input recording session. 1518a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1519a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public abstract static class RecordingSession { 1520a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo final Handler mHandler; 1521a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1522a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private final Object mLock = new Object(); 1523a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo // @GuardedBy("mLock") 1524a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private ITvInputSessionCallback mSessionCallback; 1525a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo // @GuardedBy("mLock") 1526a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private final List<Runnable> mPendingActions = new ArrayList<>(); 1527a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1528a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1529e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Creates a new RecordingSession. 1530a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1531a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param context The context of the application 1532a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1533a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public RecordingSession(Context context) { 1534a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mHandler = new Handler(context.getMainLooper()); 1535a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1536a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1537a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1538e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Informs the application that this recording session has been tuned to the given channel 1539e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * and is ready to start recording. 1540e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1541e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * <p>Upon receiving a call to {@link #onTune(Uri)}, the session is expected to tune to the 1542e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * passed channel and call this method to indicate that it is now available for immediate 1543e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * recording. When {@link #onStartRecording(Uri)} is called, recording must start with 1544e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * minimal delay. 1545b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * 1546b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * @param channelUri The URI of a channel. 1547a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1548b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang public void notifyTuned(Uri channelUri) { 1549a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 1550a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 1551a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Override 1552a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void run() { 1553a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 1554e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo if (DEBUG) Log.d(TAG, "notifyTuned"); 1555a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mSessionCallback != null) { 1556b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang mSessionCallback.onTuned(channelUri); 1557a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1558a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 1559e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo Log.w(TAG, "error in notifyTuned", e); 1560a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1561a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1562a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo }); 1563a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1564a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1565a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1566e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Informs the application that this recording session has stopped recording and created a 1567e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * new data entry in the {@link TvContract.RecordedPrograms} table that describes the newly 1568e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * recorded program. 1569a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 157025c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * <p>The recording session must call this method in response to {@link #onStopRecording()}. 157125c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * The session may call it even before receiving a call to {@link #onStopRecording()} if a 157225c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * partially recorded program is available when there is an error. 157325c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * 1574e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * @param recordedProgramUri The URI of the newly recorded program. 1575a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1576a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void notifyRecordingStopped(final Uri recordedProgramUri) { 1577a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 1578a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 1579a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Override 1580a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void run() { 1581a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 1582a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (DEBUG) Log.d(TAG, "notifyRecordingStopped"); 1583a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mSessionCallback != null) { 1584a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mSessionCallback.onRecordingStopped(recordedProgramUri); 1585a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1586a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 1587a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Log.w(TAG, "error in notifyRecordingStopped", e); 1588a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1589a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1590a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo }); 1591a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1592a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1593a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 159425c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * Informs the application that there is an error and this recording session is no longer 159525c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * able to start or continue recording. It may be called at any time after the recording 159625c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * session is created until {@link #onRelease()} is called. 159725c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * 159825c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * <p>The application may release the current session upon receiving the error code through 159925c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * {@link TvRecordingClient.RecordingCallback#onError(int)}. The session may call 160025c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * {@link #notifyRecordingStopped(Uri)} if a partially recorded but still playable program 160125c9c5edab42d6c9e9e0469ab04fb7ff87704d1cJae Seo * is available, before calling this method. 1602a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1603a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param error The error code. Should be one of the followings. 1604a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * <ul> 1605a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN} 1606a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE} 1607a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY} 1608a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * </ul> 1609a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1610150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang public void notifyError(@TvInputManager.RecordingError int error) { 1611150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang if (error < TvInputManager.RECORDING_ERROR_START 1612150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang || error > TvInputManager.RECORDING_ERROR_END) { 1613150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang Log.w(TAG, "notifyError - invalid error code (" + error 1614150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang + ") is changed to RECORDING_ERROR_UNKNOWN."); 1615150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang error = TvInputManager.RECORDING_ERROR_UNKNOWN; 1616150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang } 1617150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang final int validError = error; 1618a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 1619a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 1620a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Override 1621a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void run() { 1622a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 1623a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (DEBUG) Log.d(TAG, "notifyError"); 1624a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mSessionCallback != null) { 1625150923ac6adf3f618e9e1ac9d4d600a9c66bd812Dongwon Kang mSessionCallback.onError(validError); 1626a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1627a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 1628a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Log.w(TAG, "error in notifyError", e); 1629a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1630a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1631a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo }); 1632a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1633a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1634a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1635a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Dispatches an event to the application using this recording session. 1636a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1637a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param eventType The type of the event. 1638a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param eventArgs Optional arguments of the event. 1639a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @hide 1640a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1641a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @SystemApi 1642a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void notifySessionEvent(@NonNull final String eventType, final Bundle eventArgs) { 1643a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Preconditions.checkNotNull(eventType); 1644a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo executeOrPostRunnableOnMainThread(new Runnable() { 1645a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @MainThread 1646a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo @Override 1647a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void run() { 1648a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 1649a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")"); 1650a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mSessionCallback != null) { 1651a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mSessionCallback.onSessionEvent(eventType, eventArgs); 1652a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1653a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 1654a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Log.w(TAG, "error in sending event (event=" + eventType + ")", e); 1655a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1656a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1657a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo }); 1658a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1659a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1660a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1661e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Called when the application requests to tune to a given channel for TV program recording. 1662a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1663e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * <p>The application may call this method before starting or after stopping recording, but 1664e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * not during recording. 1665e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1666b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or 1667e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * {@link #notifyError(int)} otherwise. 1668e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1669e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * @param channelUri The URI of a channel. 1670a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1671e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo public abstract void onTune(Uri channelUri); 1672a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1673a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1674031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * Called when the application requests to tune to a given channel for TV program recording. 1675031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * Override this method in order to handle domain-specific features that are only known 1676031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * between certain TV inputs and their clients. 1677a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1678e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * <p>The application may call this method before starting or after stopping recording, but 1679031d7e838d9f026248e9e54a4aa025d2605bce78Dongwon Kang * not during recording. The default implementation calls {@link #onTune(Uri)}. 1680e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1681d48d029da43babf265fccbf5d84a06b4b275f72cJiabin * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or 1682e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * {@link #notifyError(int)} otherwise. 1683e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1684e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * @param channelUri The URI of a channel. 1685d48d029da43babf265fccbf5d84a06b4b275f72cJiabin * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped 1686d48d029da43babf265fccbf5d84a06b4b275f72cJiabin * name, i.e. prefixed with a package name you own, so that different developers 1687d48d029da43babf265fccbf5d84a06b4b275f72cJiabin * will not create conflicting keys. 1688a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1689e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo public void onTune(Uri channelUri, Bundle params) { 1690e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo onTune(channelUri); 1691a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1692a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1693a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1694e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Called when the application requests to start TV program recording. Recording must start 1695e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * immediately when this method is called. 1696a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1697b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * <p>The application may supply the URI for a TV program for filling in program specific 1698b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table. 16990cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang * A non-null {@code programUri} implies the started recording should be of that specific 17000cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang * program, whereas null {@code programUri} does not impose such a requirement and the 17014eee6a73e476cd2d82a69f3a535628901047f140Jae Seo * recording can span across multiple TV programs. In either case, the application must call 1702cd502cf7150f0fb426f7f808c7d407ce89705239Jae Seo * {@link TvRecordingClient#stopRecording()} to stop the recording. 17034eee6a73e476cd2d82a69f3a535628901047f140Jae Seo * 1704e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * <p>The session must call {@link #notifyError(int)} if the start request cannot be 1705e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * fulfilled. 17064eee6a73e476cd2d82a69f3a535628901047f140Jae Seo * 1707b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang * @param programUri The URI for the TV program to record, built by 17084eee6a73e476cd2d82a69f3a535628901047f140Jae Seo * {@link TvContract#buildProgramUri(long)}. Can be {@code null}. 1709a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1710b55c7517ba4b2c2959a0bc4d37536e7e3c8283c9Dongwon Kang public abstract void onStartRecording(@Nullable Uri programUri); 1711a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1712a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1713e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Called when the application requests to stop TV program recording. Recording must stop 1714e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * immediately when this method is called. 1715e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * 1716e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * <p>The session must create a new data entry in the 1717e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * {@link android.media.tv.TvContract.RecordedPrograms} table that describes the newly 1718e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * recorded program and call {@link #notifyRecordingStopped(Uri)} with the URI to that 1719e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * entry. 1720e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * If the stop request cannot be fulfilled, the session must call {@link #notifyError(int)}. 1721a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1722a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1723a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public abstract void onStopRecording(); 1724a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1725e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo 1726e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo /** 1727e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Called when the application requests to release all the resources held by this recording 1728e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * session. 1729e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo */ 1730e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo public abstract void onRelease(); 1731e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo 1732a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1733a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Processes a private command sent from the application to the TV input. This can be used 1734a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * to provide domain-specific features that are only known between certain TV inputs and 1735a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * their clients. 1736a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1737a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param action Name of the command to be performed. This <em>must</em> be a scoped name, 1738a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * i.e. prefixed with a package name you own, so that different developers will 1739a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * not create conflicting commands. 1740a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * @param data Any data to include with the command. 1741a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1742a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo public void onAppPrivateCommand(@NonNull String action, Bundle data) { 1743a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1744a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1745a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1746e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Calls {@link #onTune(Uri, Bundle)}. 1747a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1748a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1749e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo void tune(Uri channelUri, Bundle params) { 1750e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo onTune(channelUri, params); 1751a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1752a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1753a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1754e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo * Calls {@link #onRelease()}. 1755a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1756a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1757e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo void release() { 1758e3c11e842937f50f54c9d82363f33338dc9e261bJae Seo onRelease(); 1759a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1760a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1761a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 17624eee6a73e476cd2d82a69f3a535628901047f140Jae Seo * Calls {@link #onStartRecording(Uri)}. 1763a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1764a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 17650cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang void startRecording(@Nullable Uri programUri) { 17660cb5244e52590214ddc16dd5fc1030b5baf04726Dongwon Kang onStartRecording(programUri); 1767a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1768a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1769a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1770a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Calls {@link #onStopRecording()}. 1771a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * 1772a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1773a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo void stopRecording() { 1774a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo onStopRecording(); 1775a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1776a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1777a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1778a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo * Calls {@link #onAppPrivateCommand(String, Bundle)}. 1779a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo */ 1780a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo void appPrivateCommand(String action, Bundle data) { 1781a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo onAppPrivateCommand(action, data); 1782a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1783a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1784a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private void initialize(ITvInputSessionCallback callback) { 1785a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo synchronized(mLock) { 1786a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mSessionCallback = callback; 1787a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo for (Runnable runnable : mPendingActions) { 1788a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo runnable.run(); 1789a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1790a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mPendingActions.clear(); 1791a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1792a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1793a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1794a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private void executeOrPostRunnableOnMainThread(Runnable action) { 1795a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo synchronized(mLock) { 1796a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mSessionCallback == null) { 1797a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo // The session is not initialized yet. 1798a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mPendingActions.add(action); 1799a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } else { 1800a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (mHandler.getLooper().isCurrentThread()) { 1801a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo action.run(); 1802a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } else { 1803a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo // Posts the runnable if this is not called from the main thread 1804a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo mHandler.post(action); 1805a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1806a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1807a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1808a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1809a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 1810a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo 1811a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo /** 1812bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * Base class for a TV input session which represents an external device connected to a 181349c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * hardware TV input. 18140610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 18150610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>This class is for an input which provides channels for the external set-top box to the 181649c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * application. Once a TV input returns an implementation of this class on 181749c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * {@link #onCreateSession(String)}, the framework will create a separate session for 181849c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * a hardware TV Input (e.g. HDMI 1) and forward the application's surface to the session so 181949c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * that the user can see the screen of the hardware TV Input when she tunes to a channel from 182049c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * this TV input. The implementation of this class is expected to change the channel of the 1821e12d810e99da093d3cf38f89c81e3e8d1e75b404Dongwon Kang * external set-top box via a proprietary protocol when {@link HardwareSession#onTune} is 182249c1b69a568ce58c940e5a2b0641a2c50798cbe2Dongwon Kang * requested by the application. 18230610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 18240610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>Note that this class is not for inputs for internal hardware like built-in tuner and HDMI 18250610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 1. 18260610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 1827bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * @see #onCreateSession(String) 1828bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang */ 182966b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang public abstract static class HardwareSession extends Session { 183066b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang 183166b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang /** 183266b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * Creates a new HardwareSession. 183366b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * 183466b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang * @param context The context of the application 183566b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang */ 183666b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang public HardwareSession(Context context) { 183766b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang super(context); 183866b9e91801ba8867514fbcf0ef8f03a2f4fb8798Dongwon Kang } 1839bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1840bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang private TvInputManager.Session mHardwareSession; 1841bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang private ITvInputSession mProxySession; 1842bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang private ITvInputSessionCallback mProxySessionCallback; 1843c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang private Handler mServiceHandler; 1844bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1845bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang /** 1846bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * Returns the hardware TV input ID the external device is connected to. 18470610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * 18480610e12733875a267f59d87a2a68aebbf486066eDongwon Kang * <p>TV input is expected to provide {@link android.R.attr#setupActivity} so that 1849bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * the application can launch it before using this TV input. The setup activity may let 1850bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * the user select the hardware TV input to which the external device is connected. The ID 1851bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * of the selected one should be stored in the TV input so that it can be returned here. 1852bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang */ 1853bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public abstract String getHardwareInputId(); 1854bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1855bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang private final TvInputManager.SessionCallback mHardwareSessionCallback = 1856bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang new TvInputManager.SessionCallback() { 1857bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang @Override 1858bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public void onSessionCreated(TvInputManager.Session session) { 1859bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang mHardwareSession = session; 1860bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang SomeArgs args = SomeArgs.obtain(); 1861bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang if (session != null) { 18623eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg1 = HardwareSession.this; 18633eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg2 = mProxySession; 18643eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg3 = mProxySessionCallback; 18653eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg4 = session.getToken(); 1866731843e424a0d7091eb42d579aab6a66a74b92caDongwon Kang session.tune(TvContract.buildChannelUriForPassthroughInput( 1867731843e424a0d7091eb42d579aab6a66a74b92caDongwon Kang getHardwareInputId())); 1868bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } else { 1869bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang args.arg1 = null; 18703eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg2 = null; 18713eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg3 = mProxySessionCallback; 18723eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang args.arg4 = null; 1873bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang onRelease(); 1874bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1875c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED, args) 1876bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang .sendToTarget(); 1877bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1878bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1879bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang @Override 1880bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public void onVideoAvailable(final TvInputManager.Session session) { 1881bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang if (mHardwareSession == session) { 1882bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang onHardwareVideoAvailable(); 1883bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1884bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1885bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1886bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang @Override 1887bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public void onVideoUnavailable(final TvInputManager.Session session, 1888bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang final int reason) { 1889bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang if (mHardwareSession == session) { 1890bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang onHardwareVideoUnavailable(reason); 1891bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1892bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1893bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang }; 1894bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1895bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang /** 1896bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * This method will not be called in {@link HardwareSession}. Framework will 1897bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * forward the application's surface to the hardware TV input. 1898bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang */ 1899bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang @Override 1900bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public final boolean onSetSurface(Surface surface) { 1901bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang Log.e(TAG, "onSetSurface() should not be called in HardwareProxySession."); 1902bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang return false; 1903bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1904bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1905bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang /** 1906bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * Called when the underlying hardware TV input session calls 1907bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * {@link TvInputService.Session#notifyVideoAvailable()}. 1908bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang */ 1909bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public void onHardwareVideoAvailable() { } 1910bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 1911bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang /** 1912bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * Called when the underlying hardware TV input session calls 1913bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * {@link TvInputService.Session#notifyVideoUnavailable(int)}. 1914bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * 1915bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * @param reason The reason that the hardware TV input stopped the playback: 1916bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * <ul> 1917bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN} 1918bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} 1919bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL} 1920bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING} 1921ff1f29e1b112e68d16908b1a89225315089f8e50Dongwon Kang * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY} 1922bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang * </ul> 1923bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang */ 1924bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang public void onHardwareVideoUnavailable(int reason) { } 192578364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang 192678364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang @Override 192778364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang void release() { 192878364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang if (mHardwareSession != null) { 192978364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang mHardwareSession.release(); 193078364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang mHardwareSession = null; 193178364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang } 193278364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang super.release(); 193378364ddc047100306f0ccacc8fdad043d9a43653Dongwon Kang } 1934bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 1935bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang 193644fbbca35459ee756a531661eba53ec33419790aYoungsang Cho /** @hide */ 193744fbbca35459ee756a531661eba53ec33419790aYoungsang Cho public static boolean isNavigationKey(int keyCode) { 193844fbbca35459ee756a531661eba53ec33419790aYoungsang Cho switch (keyCode) { 193944fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_DPAD_LEFT: 194044fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_DPAD_RIGHT: 194144fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_DPAD_UP: 194244fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_DPAD_DOWN: 194344fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_DPAD_CENTER: 194444fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_PAGE_UP: 194544fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_PAGE_DOWN: 194644fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_MOVE_HOME: 194744fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_MOVE_END: 194844fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_TAB: 194944fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_SPACE: 195044fbbca35459ee756a531661eba53ec33419790aYoungsang Cho case KeyEvent.KEYCODE_ENTER: 195144fbbca35459ee756a531661eba53ec33419790aYoungsang Cho return true; 195244fbbca35459ee756a531661eba53ec33419790aYoungsang Cho } 195344fbbca35459ee756a531661eba53ec33419790aYoungsang Cho return false; 195444fbbca35459ee756a531661eba53ec33419790aYoungsang Cho } 195544fbbca35459ee756a531661eba53ec33419790aYoungsang Cho 19562c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo @SuppressLint("HandlerLeak") 19573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceHandler extends Handler { 19583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final int DO_CREATE_SESSION = 1; 1959bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang private static final int DO_NOTIFY_SESSION_CREATED = 2; 1960a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo private static final int DO_CREATE_RECORDING_SESSION = 3; 19611abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private static final int DO_ADD_HARDWARE_INPUT = 4; 19621abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private static final int DO_REMOVE_HARDWARE_INPUT = 5; 19631abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private static final int DO_ADD_HDMI_INPUT = 6; 19641abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private static final int DO_REMOVE_HDMI_INPUT = 7; 19654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee 19661abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) { 19674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee int n = mCallbacks.beginBroadcast(); 19684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee for (int i = 0; i < n; ++i) { 19694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee try { 19701abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mCallbacks.getBroadcastItem(i).addHardwareInput(deviceId, inputInfo); 19714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } catch (RemoteException e) { 19721abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo Log.e(TAG, "error in broadcastAddHardwareInput", e); 19734f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 19744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 19754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee mCallbacks.finishBroadcast(); 19764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 1977187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 19781abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private void broadcastAddHdmiInput(int id, TvInputInfo inputInfo) { 1979187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim int n = mCallbacks.beginBroadcast(); 1980187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim for (int i = 0; i < n; ++i) { 1981187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim try { 19821abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mCallbacks.getBroadcastItem(i).addHdmiInput(id, inputInfo); 1983187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } catch (RemoteException e) { 19841abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo Log.e(TAG, "error in broadcastAddHdmiInput", e); 1985187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1986187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1987187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim mCallbacks.finishBroadcast(); 1988187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 1989187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim 19901abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo private void broadcastRemoveHardwareInput(String inputId) { 1991187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim int n = mCallbacks.beginBroadcast(); 1992187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim for (int i = 0; i < n; ++i) { 1993187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim try { 19941abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo mCallbacks.getBroadcastItem(i).removeHardwareInput(inputId); 1995187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } catch (RemoteException e) { 19961abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo Log.e(TAG, "error in broadcastRemoveHardwareInput", e); 199779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo } 199879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo } 199979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo mCallbacks.finishBroadcast(); 200079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo } 200179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo 20023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 20033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public final void handleMessage(Message msg) { 20043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo switch (msg.what) { 20053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo case DO_CREATE_SESSION: { 20066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo SomeArgs args = (SomeArgs) msg.obj; 20076a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo InputChannel channel = (InputChannel) args.arg1; 20086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2; 2009187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim String inputId = (String) args.arg3; 2010bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang args.recycle(); 2011c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang Session sessionImpl = onCreateSession(inputId); 2012bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang if (sessionImpl == null) { 2013bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang try { 20143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Failed to create a session. 2015bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang cb.onSessionCreated(null, null); 2016bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } catch (RemoteException e) { 2017465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.e(TAG, "error in onSessionCreated", e); 2018bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 2019c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang return; 2020c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang } 2021c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this, 2022c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang sessionImpl, channel); 2023c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang if (sessionImpl instanceof HardwareSession) { 2024c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang HardwareSession proxySession = 2025c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang ((HardwareSession) sessionImpl); 20266e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo String hardwareInputId = proxySession.getHardwareInputId(); 20276e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo if (TextUtils.isEmpty(hardwareInputId) || 20286e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo !isPassthroughInput(hardwareInputId)) { 20296e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo if (TextUtils.isEmpty(hardwareInputId)) { 2030911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang Log.w(TAG, "Hardware input id is not setup yet."); 2031911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang } else { 20326e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo Log.w(TAG, "Invalid hardware input id : " + hardwareInputId); 2033911d0827ca67d61c141ab91e75816da94b3f414eDongwon Kang } 2034c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang sessionImpl.onRelease(); 2035c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang try { 2036c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang cb.onSessionCreated(null, null); 2037c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang } catch (RemoteException e) { 2038465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.e(TAG, "error in onSessionCreated", e); 2039bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 2040c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang return; 20413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2042c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang proxySession.mProxySession = stub; 2043c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang proxySession.mProxySessionCallback = cb; 2044c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang proxySession.mServiceHandler = mServiceHandler; 2045c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang TvInputManager manager = (TvInputManager) getSystemService( 2046c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang Context.TV_INPUT_SERVICE); 20476e4cbfd2e5ffb739269e5e4affc2b6894bc4090eJae Seo manager.createSession(hardwareInputId, 2048c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang proxySession.mHardwareSessionCallback, mServiceHandler); 2049c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang } else { 2050c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang SomeArgs someArgs = SomeArgs.obtain(); 20513eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang someArgs.arg1 = sessionImpl; 20523eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang someArgs.arg2 = stub; 20533eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang someArgs.arg3 = cb; 20543eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang someArgs.arg4 = null; 2055c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED, 2056c566ca54b10fca266216555c3b6fb56a5ac63343Dongwon Kang someArgs).sendToTarget(); 2057bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 2058bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang return; 2059bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang } 2060bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang case DO_NOTIFY_SESSION_CREATED: { 2061bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang SomeArgs args = (SomeArgs) msg.obj; 20623eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang Session sessionImpl = (Session) args.arg1; 20633eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang ITvInputSession stub = (ITvInputSession) args.arg2; 20643eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg3; 20653eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang IBinder hardwareSessionToken = (IBinder) args.arg4; 2066bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang try { 2067bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang cb.onSessionCreated(stub, hardwareSessionToken); 20683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2069465f0d6aa36f2f1db88603aa487bcba9f5af068dJae Seo Log.e(TAG, "error in onSessionCreated", e); 20703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 20713eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang if (sessionImpl != null) { 20723eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang sessionImpl.initialize(cb); 20733eefa59e37291abc72edd1c30b5469a21993dbbbDongwon Kang } 20746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo args.recycle(); 20753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 20763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2077a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo case DO_CREATE_RECORDING_SESSION: { 2078a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 2079a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg1; 2080a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo String inputId = (String) args.arg2; 2081a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo args.recycle(); 2082a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo RecordingSession recordingSessionImpl = onCreateRecordingSession(inputId); 2083a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo if (recordingSessionImpl == null) { 2084a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 2085a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo // Failed to create a recording session. 2086a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo cb.onSessionCreated(null, null); 2087a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 2088a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Log.e(TAG, "error in onSessionCreated", e); 2089a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 2090a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo return; 2091a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 2092a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this, 2093a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo recordingSessionImpl); 2094a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo try { 2095a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo cb.onSessionCreated(stub, null); 2096a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } catch (RemoteException e) { 2097a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo Log.e(TAG, "error in onSessionCreated", e); 2098a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 2099a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo recordingSessionImpl.initialize(cb); 2100a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo return; 2101a826d0172aae5e91d633ffe606059a2355fbf7e5Jae Seo } 21021abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo case DO_ADD_HARDWARE_INPUT: { 2103187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj; 2104187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim TvInputInfo inputInfo = onHardwareAdded(hardwareInfo); 2105187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim if (inputInfo != null) { 21061abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo broadcastAddHardwareInput(hardwareInfo.getDeviceId(), inputInfo); 21074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 21084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee return; 21094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 21101abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo case DO_REMOVE_HARDWARE_INPUT: { 21114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj; 21124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee String inputId = onHardwareRemoved(hardwareInfo); 21134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (inputId != null) { 21141abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo broadcastRemoveHardwareInput(inputId); 21154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 21164f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee return; 21174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee } 21181abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo case DO_ADD_HDMI_INPUT: { 2119546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 2120546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo); 21214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee if (inputInfo != null) { 21221abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo broadcastAddHdmiInput(deviceInfo.getId(), inputInfo); 2123187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 2124187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim return; 2125187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 21261abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo case DO_REMOVE_HDMI_INPUT: { 2127546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj; 2128546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo String inputId = onHdmiDeviceRemoved(deviceInfo); 2129187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim if (inputId != null) { 21301abbbcd33efb8e5897c0fad5b6dd3af9a6b49b0dJae Seo broadcastRemoveHardwareInput(inputId); 2131187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 2132187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim return; 2133187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim } 21343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo default: { 21353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.w(TAG, "Unhandled message code: " + msg.what); 21363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 21373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 21383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 21393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 21403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 21413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo} 2142