HdmiControlService.java revision 3059556f6092af0e292d4b3cff97ec772d2d6bd1
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 19ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; 20ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 265b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 305b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL; 315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 3338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 347ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 39c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 407d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 4160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 43d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 44d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 46d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 48b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kimimport android.hardware.hdmi.IHdmiMhlVendorCommandListener; 4912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 50ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 51119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 52a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 537fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager; 547fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager.TvInputCallback; 555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 5642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 60e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 6138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 6278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 6338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 647d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 667ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 718b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 7278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 74959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 76a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 787e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 80f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kimimport com.android.server.hdmi.SelectRequestBuffer.DeviceSelectRequest; 81f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kimimport com.android.server.hdmi.SelectRequestBuffer.PortSelectRequest; 820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 83b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 84b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 85959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.FileDescriptor; 86959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.PrintWriter; 8778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 88f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 890340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 9002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 911ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 92a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 995fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale HONG_KONG = new Locale("zh", "HK"); 1005fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale MACAU = new Locale("zh", "MO"); 1010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 102c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 10378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 104fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 105fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 106fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 107fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 108fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 109b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo static final int INITIATED_BY_HOTPLUG = 4; 110fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 111e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // The reason code representing the intent action that drives the standby 112e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // procedure. The procedure starts either by Intent.ACTION_SCREEN_OFF or 113e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // Intent.ACTION_SHUTDOWN. 114e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim static final int STANDBY_SCREEN_OFF = 0; 115e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim static final int STANDBY_SHUTDOWN = 1; 116e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim 117d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 118d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 119d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 120d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 121d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 122d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 123d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 124ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1264fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1294fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 130d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 131d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 132d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 133d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 13402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 13502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 13602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 13802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 13902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 14002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 14102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 14202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 14302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 14402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 14502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1461ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 147f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 14938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 150f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 15138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 15238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 15338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 154e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandby(STANDBY_SCREEN_OFF); 15538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 15738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 15838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 15938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 16038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 16138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1621ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1635fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim String language = getMenuLanguage(); 1641ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1651ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1661ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1671ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 168e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim case Intent.ACTION_SHUTDOWN: 169e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim if (isPowerOnOrTransient()) { 170e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandby(STANDBY_SHUTDOWN); 171e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim } 172e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim break; 17338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1755fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim 1765fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private String getMenuLanguage() { 1775fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim Locale locale = Locale.getDefault(); 1785fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { 1795fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Android always returns "zho" for all Chinese variants. 1805fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Use "bibliographic" code defined in CEC639-2 for traditional 1815fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Chinese used in Taiwan/Hong Kong/Macau. 1825fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return "chi"; 1835fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } else { 1845fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return locale.getISO3Language(); 1855fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 1865fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 18738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 18838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 19478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 19578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 19678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 19978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 20078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 2014893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 20278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 20378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 20478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 205f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 2064893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 2076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 2086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 2096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 210f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 211119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 212119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 213119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 214119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 2159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 2169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 2179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 218b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 21912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 220b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 22192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 22292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 22392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 22492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 22592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 2264d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 2274d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 2284d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2294d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2304d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2314d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 232ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 233ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 234ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 235ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2364893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 241f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 242f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 243f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2512b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 25230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2532b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2542b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 25530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2562b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 257e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 258e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 259e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 26075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 26175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 26238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 263c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 26438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 26538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2661ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2671ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2681ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 26938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 27038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 271fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 272fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 273fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 274867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 275867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 276867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 277f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 278f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 279f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 280f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 281b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim // List of records for MHL Vendor command listener to handle the caller killed in action. 282f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 283b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final ArrayList<HdmiMhlVendorCommandListenerRecord> 284b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords = new ArrayList<>(); 285f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 286f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 287f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 288f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 289f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 290781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim private HdmiMhlControllerStub mMhlController; 291f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 2927fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Nullable 2937fa3a66470d2133796defd14a0600578758882acJinsuk Kim private TvInputManager mTvInputManager; 2947fa3a66470d2133796defd14a0600578758882acJinsuk Kim 295e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim @Nullable 296e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private PowerManager mPowerManager; 297e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 298f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 299f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 300e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 301e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 302e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 303e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 304964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Set to true if the logical address allocation is completed. 305964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean mAddressAllocated = false; 306964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 307964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Buffer for processing the incoming cec messages while allocating logical addresses. 308964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private final class CecMessageBuffer { 309964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private List<HdmiCecMessage> mBuffer = new ArrayList<>(); 310964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 311964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void bufferMessage(HdmiCecMessage message) { 312964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim switch (message.getOpcode()) { 313964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 314964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferActiveSource(message); 315964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 316964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_IMAGE_VIEW_ON: 317964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_TEXT_VIEW_ON: 318964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferImageOrTextViewOn(message); 319964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 320964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Add here if new message that needs to buffer 321964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim default: 322964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Do not need to buffer messages other than above 323964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 324964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 325964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 326964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 327964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void processMessages() { 328964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (final HdmiCecMessage message : mBuffer) { 329964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim runOnServiceThread(new Runnable() { 330964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim @Override 331964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void run() { 332964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim handleCecCommand(message); 333964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 334964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim }); 335964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 336964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 337964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 338964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 339964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferActiveSource(HdmiCecMessage message) { 340964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) { 341964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 342964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 343964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 344964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 345964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferImageOrTextViewOn(HdmiCecMessage message) { 346964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) && 347964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) { 348964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 349964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 350964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 351964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 352964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Returns true if the message is replaced 353964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) { 354964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (int i = 0; i < mBuffer.size(); i++) { 355964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim HdmiCecMessage bufferedMessage = mBuffer.get(i); 356964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (bufferedMessage.getOpcode() == opcode) { 357964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.set(i, message); 358964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 359964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 360964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 361964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return false; 362964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 363964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 364964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 365f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private final CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(); 366f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 367f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer(); 368964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 3690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 3700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 3717d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 3725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 3730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 3757d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 3767d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 3777d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 3787d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 3797d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 3807d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 3817d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 3827d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 3837d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 3847d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3857d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3867d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 3877d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3887d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 3890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 3900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 3912f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 392c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 3937ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 3947ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 39508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 3968b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 397a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 3983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 399a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 400fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 401a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 402a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 4030792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 40408f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim return; 4050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 4060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 407781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim mMhlController = HdmiMhlControllerStub.create(this); 408f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 4090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 4100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 411ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 412f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 413f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 41475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 4158692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 41663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 417f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 4180608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register broadcast receiver for power state change. 41938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 42038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 42138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 4223059556f6092af0e292d4b3cff97ec772d2d6bd1Rob McConnell filter.addAction(Intent.ACTION_SHUTDOWN); 4231ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 4241ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 4250608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 4260608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register ContentObserver to monitor the settings change. 4270608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo registerContentObserver(); 42838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 4295b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); 4307ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 43138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 4327fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Override 4337fa3a66470d2133796defd14a0600578758882acJinsuk Kim public void onBootPhase(int phase) { 4347fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 4357fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager = (TvInputManager) getContext().getSystemService( 4367fa3a66470d2133796defd14a0600578758882acJinsuk Kim Context.TV_INPUT_SERVICE); 437e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 4387fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4397fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4407fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4417fa3a66470d2133796defd14a0600578758882acJinsuk Kim TvInputManager getTvInputManager() { 4427fa3a66470d2133796defd14a0600578758882acJinsuk Kim return mTvInputManager; 4437fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4447fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4457fa3a66470d2133796defd14a0600578758882acJinsuk Kim void registerTvInputCallback(TvInputCallback callback) { 4467fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4477fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.registerCallback(callback, mHandler); 4487fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4497fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4507fa3a66470d2133796defd14a0600578758882acJinsuk Kim void unregisterTvInputCallback(TvInputCallback callback) { 4517fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4527fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.unregisterCallback(callback); 4537fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4547fa3a66470d2133796defd14a0600578758882acJinsuk Kim 455e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim PowerManager getPowerManager() { 456e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return mPowerManager; 457e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 458e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 45925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 46025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 46125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 4620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo private void onInitializeCecComplete(int initiatedBy) { 463fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 464fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 465fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 466fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 467fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 468de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 4695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 4700608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4710608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo int reason = -1; 4720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo switch (initiatedBy) { 4730608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_BOOT_UP: 4740608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; 4750608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4760608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_ENABLE_CEC: 4770608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; 4780608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4790608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_SCREEN_ON: 4800608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_WAKE_UP_MESSAGE: 4810608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; 4820608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4830608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4840608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (reason != -1) { 4850608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(true, reason); 48625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 48725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 48825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 4895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 4905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 4915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 4925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 4935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 4945008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 4955008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 4965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 4975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 4985691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 4995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 5005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 5015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 5055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 5065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 5075008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5085008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 509f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 5105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 5115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 5125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 5135008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 5145008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 5155008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 5165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 5175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 519de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 520de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim tv().setAutoWakeup(enabled); 521de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 522350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 5235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 525e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim for (int type : mLocalDevices) { 526e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 527dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo if (localDevice != null) { 528dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo localDevice.setAutoDeviceOff(enabled); 529dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo } 530de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 5315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 5325008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5335008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 53408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 5355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 537f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 5385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 5445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 5455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5477ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 5487ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 5507ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 5517ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 5527ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 5537ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5545008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 5555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 557fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 558964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = false; 5595008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 5605b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage)); 561b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo initializeLocalDevices(initiatedBy); 562a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 563a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 564a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 565b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void initializeLocalDevices(final int initiatedBy) { 566a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 567b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // A container for [Device type, Local device info]. 568b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 569b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (int type : mLocalDevices) { 5706f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 5716f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (localDevice == null) { 5726f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim localDevice = HdmiCecLocalDevice.create(this, type); 5736f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 5743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 575b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo localDevices.add(localDevice); 576b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 5776f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // It's now safe to flush existing local devices from mCecController since they were 5786f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // already moved to 'localDevices'. 5796f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim clearLocalDevices(); 580b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocateLogicalAddress(localDevices, initiatedBy); 581b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 582b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 583b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo @ServiceThreadOnly 584b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void allocateLogicalAddress(final ArrayList<HdmiCecLocalDevice> allocatingDevices, 585b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int initiatedBy) { 586b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo assertRunOnServiceThread(); 58789ec14e48f4a1bdf291cda9fba7b8172f55a2447Yuncheol Heo mCecController.clearLogicalAddress(); 588b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>(); 589b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int[] finished = new int[1]; 590964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = allocatingDevices.isEmpty(); 591964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 592f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // For TV device, select request can be invoked while address allocation or device 593f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // discovery is in progress. Initialize the request here at the start of allocation, 594f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // and process the collected requests later when the allocation and device discovery 595f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // is all completed. 596f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.clear(); 597f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 598b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (final HdmiCecLocalDevice localDevice : allocatingDevices) { 599b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo mCecController.allocateLogicalAddress(localDevice.getType(), 6003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 6013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 6023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 603c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 6043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 6053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 606410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 607410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 608410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 609410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 6103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 6113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 6123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 613b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocatedDevices.add(localDevice); 6143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6164893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 617b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (allocatingDevices.size() == ++finished[0]) { 618964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = true; 619b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (initiatedBy != INITIATED_BY_HOTPLUG) { 620b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // In case of the hotplug we don't call onInitializeCecComplete() 621b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // since we reallocate the logical address only. 6220608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo onInitializeCecComplete(initiatedBy); 623b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 624b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo notifyAddressAllocated(allocatedDevices, initiatedBy); 625964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.processMessages(); 6263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 6293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 632a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 633b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) { 634a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 635b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (HdmiCecLocalDevice device : devices) { 636b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int address = device.getDeviceInfo().getLogicalAddress(); 637fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 6383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 639f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (isTvDeviceEnabled()) { 640f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim tv().setSelectRequestBuffer(mSelectRequestBuffer); 641f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 6423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 6450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 646a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6472b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 648a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 6500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 6510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 6520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 6530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 6540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 6550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 6572b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 6582b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6592b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 66030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 66130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 662e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 6632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 66430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 66530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 666e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 6670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 66830c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 66930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 670e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 6710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 672f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 673f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 674f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 675f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 676f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 6770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 678f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 6790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 680f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 681f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 682f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 683f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 684f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 685f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 686f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 687f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 688f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 689f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 690f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 691f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 692f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 6932b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6942b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 695f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 6960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 6982738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 6992738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 7002738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 7012738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 7020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 7030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 7040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 7050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 7060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 7070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 7080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 7092b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 7100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 7110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 712e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 713401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 714401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 715401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 716401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 717401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 718401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 719401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 720c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 721401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 722401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 723401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 724401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 725401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 726401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 727401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 728401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 729401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 730401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 731401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 732c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 7332b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 734401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 735401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 73609ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 7372b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 73809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 73909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 740401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 741e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 742e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 743e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 744e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 745e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 746e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 747e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 748e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 749e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 750e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 751e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 752e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 753e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 754e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 755e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 75667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 757e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 758c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 759c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 7603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 7613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 7633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 7643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 7673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 7683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 7703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 7713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 773a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 77461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 7750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 776de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return tv() == null ? null : tv().getCecDeviceInfo(logicalAddress); 777a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 778a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 7796ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim @ServiceThreadOnly 7806ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiDeviceInfo getDeviceInfoByPort(int port) { 7816ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim assertRunOnServiceThread(); 7826ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiMhlLocalDeviceStub info = mMhlController.getLocalDevice(port); 7836ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim if (info != null) { 7846ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return info.getInfo(); 7856ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7866ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return null; 7876ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7886ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim 7893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 790092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 791092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 792092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 793092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 794092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 795092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 796092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 79760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 79860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 79960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 800339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 8012b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 8022b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 80360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 80460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 80560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 80660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 8077b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim @ServiceThreadOnly 8087b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim boolean isConnected(int portId) { 8097b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim assertRunOnServiceThread(); 8107b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim return mCecController.isConnected(portId); 8117b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim } 8127b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim 81379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 81467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 81567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 81667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 81763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 81863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 81963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 82063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 82163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 82263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 82363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 82463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 82563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 82663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 82767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 828c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 829c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 830c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 831d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 832c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 833a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 834d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 835a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8364c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) { 8375f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 8385f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 8392e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.error("Invalid message type:" + command); 8405f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 8415f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 8425f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 8435f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 844d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 845d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 846a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 847d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 848a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8495f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 850c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 851c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 8526aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 8536aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 8546aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 8556aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 8566aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 8576aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 8586aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 8596aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 8606aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 8616aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 8626aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 8636aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 864a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 865a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 866a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 867964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!mAddressAllocated) { 868964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.bufferMessage(message); 869964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 870964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 8714c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int errorCode = mMessageValidator.isValid(message); 8724c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode != HdmiCecMessageValidator.OK) { 873a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // We'll not response on the messages with the invalid source or destination 874a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // or with parameter length shorter than specified in the standard. 8754c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode == HdmiCecMessageValidator.ERROR_PARAMETER) { 8764c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); 8774c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo } 8784c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return true; 87975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 880092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 881092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 882092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 8831481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim void setAudioReturnChannel(int portId, boolean enabled) { 8841481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim mCecController.setAudioReturnChannel(portId, enabled); 88560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 88660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 887a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 888092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 889a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 890092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 89179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 892c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 893092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 894092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 895092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 89660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 897c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 8982e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unhandled cec command:" + message); 8993a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 900092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 901a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 902a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 90367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 90467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 90567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 906ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 90767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 90867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 909a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 910ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 91160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 912b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 913b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (connected && !isTvDevice()) { 914b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 915b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo for (int type : mLocalDevices) { 916b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 917b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (localDevice == null) { 918b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice = HdmiCecLocalDevice.create(this, type); 919b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice.init(); 920b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo } 921b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevices.add(localDevice); 922b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 923b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); 924b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 925b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 92679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 927ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 92860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 929ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 93067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 93167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 93202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 93302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 93402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 93502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 93602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 9371de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 9380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 93902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 9400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 94102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 942a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 9431de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 9441de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 945a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 9461de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 9471de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 9480f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 9500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 951c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 9520f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 9530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 9540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 955c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 9560f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 9570f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 9580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9590f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 96002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 96102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 96260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 96360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 96460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 96560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 96660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 96779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 96879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 96979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 97079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 97179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 972b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 973b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 974b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 975b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 976b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 977b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 978b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 979b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 980b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 981b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 982b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 983b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 984b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 9851a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 986b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 9873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 9883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 989ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 990f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 991f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 992f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 993f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 994f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 995ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 996ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 997ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 998410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 99942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 100042c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 100161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 10022b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 10032b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 10043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 10053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 10067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 10077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 10087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 100993eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim // Hotplug event is used to add/remove MHL devices as TV input. 10107df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 10113b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); 10123b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); 10137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 10147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 10157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 10167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 101793eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); 101893eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 10197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 10203b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); 10217df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 10227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 102393eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 102493eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 10257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 10267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 10277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10287df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 1029ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 10307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1033a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusModeChanged(int portId, int busmode) { 10347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10353b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1037a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setBusMode(busmode); 10387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1039a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus mode change[portId:" + portId + 1040a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim ", busmode:" + busmode + "]"); 10417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10447df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1045a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusOvercurrent(int portId, boolean on) { 10467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10473b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10487df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1049a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.onBusOvercurrentDetected(on); 10507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1051a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus overcurrent event[portId:" + portId + "]"); 10527df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10537df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10547df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10557df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1056a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlDeviceStatusChanged(int portId, int adopterId, int deviceId) { 10577df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10583b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1059ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 10607df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1061a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setDeviceStatusChange(adopterId, deviceId); 10627df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1063a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for device status event[portId:" 10647df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 10657df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10667df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10677df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 1068ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 1069ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 1070ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 1071ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 10723b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim SparseArray<HdmiMhlLocalDeviceStub> devices = mMhlController.getAllLocalDevices(); 1073ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 10743b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = devices.valueAt(i); 1075ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 1076ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 1077ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 1078ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 1079ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1080ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 1081ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1082ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1083ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1084ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 1085ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1086ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1087ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1088ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 1089ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 1090ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1091ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1092b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private class HdmiMhlVendorCommandListenerRecord implements IBinder.DeathRecipient { 1093b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final IHdmiMhlVendorCommandListener mListener; 1094f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1095b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public HdmiMhlVendorCommandListenerRecord(IHdmiMhlVendorCommandListener listener) { 1096f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 1097f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1098f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1099f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 1100f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 1101b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.remove(this); 1102f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1103f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1104f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 110578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 110678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 110778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 110878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 110978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 111078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 111178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 111278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 111378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 111478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 111578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 111678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 111778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 111878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 111978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11203cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 11213cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 11223cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public boolean equals(Object obj) { 11233cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!(obj instanceof HotplugEventListenerRecord)) return false; 11243cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (obj == this) return true; 11253cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HotplugEventListenerRecord other = (HotplugEventListenerRecord) obj; 11263cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return other.mListener == this.mListener; 11273cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 11283cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 11293cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 11303cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public int hashCode() { 11313cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return mListener.hashCode(); 11323cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 113378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 11366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 11376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 11396d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 11406d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1143ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 11446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 11456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 11466d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11486d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11496d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1150ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 115138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 1152ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1153ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 1154ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 1155ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1156ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1157ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1158ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 1159ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 1161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1162ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1165119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 1166119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 1167119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 1168119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1169119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 1170119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 1171119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 1172119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1173119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1174119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 1176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1177119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 1178119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1179119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1180119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1181119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 118212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 1183f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 1184f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1185f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 1186f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1187f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1188f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1189b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1190b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 1191b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1192f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 1193b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1194b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1195b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1196b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 119778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 119878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 119978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 120178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 120278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 120378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 120478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 12050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 12060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 12070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 12080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 120978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 12100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 121178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 121278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 121378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 121461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 1215b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 12167e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 12177e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 12187e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 12197e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 12207e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12217e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 12227e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 122361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 122461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 122561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 12267e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12277e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 122861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 12297640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim HdmiDeviceInfo info = tv.getSafeDeviceInfoByPath(activePath); 1230d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId()); 12317e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12327e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 12337e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12347e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 12357e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 12368960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1237a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1238a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1239a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1240a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 124172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 124272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 124372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 124472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 124579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1246a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1247f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (!mAddressAllocated) { 1248f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.set(SelectRequestBuffer.newDeviceSelect( 1249f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim HdmiControlService.this, deviceId, callback)); 1250f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim return; 1251f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 1252a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1253c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1254a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1255a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 12563b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId); 1257f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1258f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1259f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 126087f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 126187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1262f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1263f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1264f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1265f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 12667c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1267f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 126887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 12698960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1270a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1271a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1272a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1273a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1274a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1275a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1276a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1277a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1278a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1279a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 128072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 128172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 128272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 128372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1284a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1285a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1286f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (!mAddressAllocated) { 1287f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect( 1288f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim HdmiControlService.this, portId, callback)); 1289f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim return; 1290f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 1291a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1292c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1293a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1294a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 12958333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1296a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1297a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1298a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1299a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1300a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1301c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1302a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1303a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1304a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1305a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 13063b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(mActivePortId); 1307f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1308f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1309f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 13104612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 13114612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 13124612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 13134612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 13144612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 13154612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 13164612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 13174612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1318a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1319a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1320a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1321a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1322a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1323a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 13247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 132578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 13267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 13277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 13287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 13297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 13307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 133278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 133378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 133478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 133678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 13377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 13387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 13397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 13407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 13417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 134378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 134478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 134578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 134778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1348f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 134978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 135078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 135178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 135378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1354f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 135578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 13566d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 13596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1360f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 13616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 13656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 13662738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 13676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1368ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1369ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1370ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1371ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1372ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1373ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1374ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1375ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1376e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1377ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1378ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1379ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1380ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1381ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1382ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1383ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1384ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1385ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1386377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1387ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1388ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1389ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1390ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1391ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1392ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1393ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1394ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1395ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1396ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1397ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1398c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1399ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1400ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1401ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1402ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1403ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1404ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1405ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1406ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1407ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1408ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1409ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1410ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1411ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1412ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1413ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1414ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1415ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1416ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1417ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1418ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 141992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 142092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 14219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 14229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 14239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 14249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 14269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 142761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 14289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 14299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 14309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 14319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1432ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1433ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1434ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1435ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1436ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 14379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1440bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // Returns all the CEC devices on the bus including system audio, switch, 1441bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // even those of reserved type. 1442bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @Override 1443bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim public List<HdmiDeviceInfo> getDeviceList() { 1444bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim enforceAccessPermission(); 1445bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1446bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim synchronized (mLock) { 1447bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return (tv == null) 1448bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1449bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim : tv.getSafeCecDevicesLocked(); 1450bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1451bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1452bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 14539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 145441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 145541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 145641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 145741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 145841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 145941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 146041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 146141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 146241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 146341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 146441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 146541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 146641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 146741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 146841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 146941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 147041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 147141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 147241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 147341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 147441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 147541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 147641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 147741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 147841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 147941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 148041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 148141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 148241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 148341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 148441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 148541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 148641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1487a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1488a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1489a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1490a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1491a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1492a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1493a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 149438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1495a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1496a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1497a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1498a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1499a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1500160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1501160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 15024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 15034d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 15044d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 15054d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 15064d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15074d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 15084d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1509119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1510119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1511119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1512119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1513119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1514f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1515119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1516119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1517119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1518119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1519119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1520119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1521119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1522119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1523119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1524119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1525119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1526119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1527119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1528119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1529119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1530119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1531119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1532119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1533119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1534119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1535119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1536119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1537119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1538119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 153912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1540a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1541a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1542d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void sendStandby(final int deviceType, final int deviceId) { 1543d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim enforceAccessPermission(); 1544d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim runOnServiceThread(new Runnable() { 1545d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1546d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void run() { 154761c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim HdmiMhlLocalDeviceStub mhlDevice = mMhlController.getLocalDeviceById(deviceId); 154861c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim if (mhlDevice != null) { 154961c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mhlDevice.sendStandby(); 155061c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim return; 155161c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim } 1552d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1553d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (device == null) { 1554d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim Slog.w(TAG, "Local device not available"); 1555d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1556d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1557d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim device.sendStandby(deviceId); 1558d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1559d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim }); 1560d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1561d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 1562d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 156312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 1564b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 156512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1566b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1567b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1568b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1569b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1570b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1571b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1572b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1573b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1574de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1575de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1576b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1577b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1578b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1579b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1580b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1581b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1582b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1583b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1584b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1585b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1586b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1587b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1588b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1589de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1590de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1591b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1592b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1593b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1594b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1595b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1596a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1597a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1598a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1599b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1600b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1601b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1602b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1603b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1604b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1605de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1606de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1607b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1608b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1609b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1610b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1611b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1612bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1613bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1614bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1615b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1616b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1617b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1618b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1619b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1620b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1621de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1622de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1623b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1624b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1625b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1626b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1627b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1628a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1629f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1630f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1631b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void sendMhlVendorCommand(final int portId, final int offset, final int length, 1632f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1633f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1634f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1635f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1636f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1637f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1638f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1639f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1640f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 16413b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1642f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1643f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1644f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1645f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1646b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlController.sendVendorCommand(portId, offset, length, data); 1647f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1648f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1649f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1650f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1651f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1652b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void addHdmiMhlVendorCommandListener( 1653b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim IHdmiMhlVendorCommandListener listener) { 1654f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1655b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiControlService.this.addHdmiMhlVendorCommandListener(listener); 1656f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1657959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1658959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1659959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1660959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1661959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1662959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1663959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1664959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1665959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1666959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1667959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1668959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1669959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1670959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 167161c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 167261c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.println("mMhlController: "); 167361c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.increaseIndent(); 167461c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mMhlController.dump(pw); 167561c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.decreaseIndent(); 167661c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 1677959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1678959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1679959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1680959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1681959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1682959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1683959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1684959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 168578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 168678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1687a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 168879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 168979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 169079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 16917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 16927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1693c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 16947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 16957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 169679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 169778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 169878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1699a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 170079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 170179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 170279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 17037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 17047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1705c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 17067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 17077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 170879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 170978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 17113cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim private void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 17123cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 171378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 171478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 171578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 171678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 171778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 171878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 172078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 172178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 17223cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 17233cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // Inform the listener of the initial state of each HDMI port by generating 17243cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // hotplug events. 17253cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim runOnServiceThread(new Runnable() { 17263cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 17273cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public void run() { 17283cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 17293cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!mHotplugEventListenerRecords.contains(record)) return; 17303cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17313cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim for (HdmiPortInfo port : mPortInfo) { 17323cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(port.getId(), 17333cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim mCecController.isConnected(port.getId())); 17343cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 17353cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim invokeHotplugEventListenerLocked(listener, event); 17363cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17373cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17383cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17393cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim }); 174078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 174178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 174278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 174378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 174478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 174578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 174678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 174778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 174878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 174978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 175078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 175178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 175278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 17537fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 17546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 17554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 17564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 17574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 17584893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 17604893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 17614893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 17634893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 17644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17654893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17664893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 176761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 17684893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1769f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 17704893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1771f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 17724893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 17746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17756d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17766d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17786d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1779ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1780ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1781ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1782ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1783ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1784ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1785ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1786ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1787ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1788ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1789ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1790ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1791ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1792ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1793ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1794ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1795ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1796ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1797ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1798ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1799ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1800ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1801ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1802ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1803ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1804ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1805ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 18069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1807f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1808f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1809f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1810f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1811f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1812f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 18139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 18149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 18159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1816f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 18179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 18219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 18229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1823f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 18249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 18259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 18269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 18279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 18289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 18299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 183361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 18349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1835f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 18369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1837f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 18389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 18399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 18409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 184512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1846b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1847f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1848b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 184912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1850b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 185112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1852b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1853b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1854b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1855b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1856b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1857b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1858f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 185912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1860f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 186112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 186212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1863b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1864b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1865b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1866b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1867b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1868b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1869326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeOneTouchRecordResult(int recorderAddress, int result) { 187012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1871f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 187212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1873326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(recorderAddress, result); 187412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 187512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 187612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 187712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 187812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 187912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 188012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1881326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeTimerRecordingResult(int recorderAddress, int result) { 188212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1883f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 188412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1885326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(recorderAddress, result); 188612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1887e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1888e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1889e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1890e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1891e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1892e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1893326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeClearTimerRecordingResult(int recorderAddress, int result) { 1894e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1895f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1896e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1897326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(recorderAddress, 1898326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang result); 1899e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1900e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 190112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 19067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 19077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 19087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 19097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 19107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 19117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 19127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 191363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1914f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1915ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1916ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1917ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1918ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1919ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1920ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1921ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1922ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 19234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 19244893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 192560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1926f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1927f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 192860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 192960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 193060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 193160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 19324893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 193360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 193460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 193560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 193660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 193760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 193860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1939e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1940e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 1941f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim public HdmiCecLocalDeviceTv tv() { 194261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 194379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 194479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1945e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1946b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); 1947e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1948e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 1949de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim boolean isTvDeviceEnabled() { 1950de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return isTvDevice() && tv() != null; 1951de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 1952de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim 195379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1954c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 195561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 195660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1957a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1958a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1959a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1960a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 196192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 196292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 196392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 196492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 196592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 196692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 196738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1968f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 196938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1970f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 197138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 197238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 197338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1974f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 197538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1976f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1977c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1978c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 197938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 198038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1981f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 198238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1983f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1984c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1985c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 198638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 198738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1988f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 198938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1990f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1991c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 199238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 199338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 199438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 199538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 199638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1997fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 1998280a64e793d081847c5dcea23ed9be38aa5332d2Dianne Hackborn mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE"); 199938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 200038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 200138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 200238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 200338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 200438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 200538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 200638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 2007e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 200838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 200938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 201038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 201138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 201238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 201338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 201438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 2015c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 201638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 2017a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 2018fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 2019fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 2020fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 2021fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 2022fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 2023a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 202438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 202538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 202638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 202738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 202838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 202938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 203038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2031e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim private void onStandby(final int standbyAction) { 203238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 2033e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim if (!canGoToStandby()) return; 2034c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 20350608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 20360608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); 20374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 20394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 20404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 20414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 20424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 20434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 20444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 2045e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandbyCompleted(standbyAction); 20464b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 20474b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 20484b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 20494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 20524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2054e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private boolean canGoToStandby() { 2055e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2056e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim if (!device.canGoToStandby()) return false; 2057e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2058e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return true; 2059e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2060e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 20611ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 20621ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 20631ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 20641ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 20651ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2066de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 20671ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 20685b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language)); 20691ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 20701ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 20711ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2072f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 2073f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 2074f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2075f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 2076f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 2077f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 20784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 2079350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 2080350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2081350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 2082350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 208338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2084350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 2085f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 208638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 208738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 208838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 20894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 20904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 20914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 20924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 20934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 20954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 20964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2099e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim private void onStandbyCompleted(int standbyAction) { 210038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 21014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 21024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2103c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 210438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 210538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2106c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 210738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2108e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim device.onStandby(mStandbyMessageReceived, standbyAction); 210938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 211038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 2111964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = false; 21125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 21135b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED); 211438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 21154d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 2116119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 2117119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 2118119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 2119119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 2120119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2121119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 2122119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 2123119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2124119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2125119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 2126119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2127119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2128119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 21290608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, 21300608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo byte[] params, boolean hasVendorId) { 2131119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2132d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (mVendorCommandListenerRecords.isEmpty()) { 2133d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return false; 2134d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 2135119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 2136119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 2137119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 2138119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2139119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 21400608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); 2141119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2142119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 2143119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2144119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2145d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return true; 2146119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2147119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2148119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 21490608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { 21500608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo synchronized (mLock) { 21510608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (mVendorCommandListenerRecords.isEmpty()) { 21520608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return false; 21530608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21540608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 21550608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo try { 21560608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onControlStateChanged(enabled, reason); 21570608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } catch (RemoteException e) { 21580608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); 21590608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21600608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21610608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return true; 21620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21630608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21640608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 2165b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { 2166b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiMhlVendorCommandListenerRecord record = 2167b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim new HdmiMhlVendorCommandListenerRecord(listener); 2168f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2169f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 2170f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2171f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 2172f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 2173f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2174f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2175f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2176b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.add(record); 2177f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2178f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2179f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2180b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim void invokeMhlVendorCommandListeners(int portId, int offest, int length, byte[] data) { 2181f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2182b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim for (HdmiMhlVendorCommandListenerRecord record : mMhlVendorCommandListenerRecords) { 2183f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2184f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 2185f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2186b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim Slog.e(TAG, "Failed to notify MHL vendor command", e); 2187f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2188f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2189f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2190f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2191f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 21924d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 21934d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 21944d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 21954d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21964d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 21984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 21994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 22004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 22014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2205350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 22065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 22075008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 22085008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 22095008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 22105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 22115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 22124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 22134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 22154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 22164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 22174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 2219f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo enableHdmiControlService(); 2220f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 22214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2222f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Call the vendor handler before the service is disabled. 2223f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 2224f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 2225f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Post the remained tasks in the service thread again to give the vendor-issued-tasks 2226f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // a chance to run. 2227f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo runOnServiceThread(new Runnable() { 2228f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2229f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2230f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableHdmiControlService(); 2231f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2232f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2233f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 2234f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2235f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2236f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2237f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void enableHdmiControlService() { 2238f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 2239f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED); 2240f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2241f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 2242f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2243f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2244f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2245f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void disableHdmiControlService() { 2246f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableDevices(new PendingActionClearedCallback() { 2247f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2248f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void onCleared(HdmiCecLocalDevice device) { 2249f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo assertRunOnServiceThread(); 2250f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.flush(new Runnable() { 2251f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2252f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2253f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.setOption(OPTION_CEC_ENABLE, DISABLED); 2254f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED); 2255f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo clearLocalDevices(); 2256f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2257f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2258f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2259f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 22604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2261867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2262867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 2263867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 2264867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 2265867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 2266e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2267e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 2268e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 2269e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 2270e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2271e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2272e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2273e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 2274e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2275e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 2276e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2277e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2278e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2279e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 2280e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2281e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 2282e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2283e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2284e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 2285e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 2286e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 2287e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 2288e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 2289e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 2290e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2291e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 2292e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2293de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (tv() == null) return; 2294e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 2295cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 2296cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 2297cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim @Override 2298cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim public void onComplete(int result) throws RemoteException { 2299cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 2300cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // This effectively sets the port to invalid one if the switching is for 2301cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // RAP[ContentOff]. 2302cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim setLastInputForMhl(lastInput); 2303cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2304cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim }); 2305cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2306e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 2307e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 2308e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 2309e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2310e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 2311f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 2312e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 2313e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 23143b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 2315cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim HdmiDeviceInfo info = (device != null) ? device.getInfo() 2316cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim : mPortDeviceMap.get(portId, HdmiDeviceInfo.INACTIVE_DEVICE); 2317e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 2318867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 231908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 2320e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 2321f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 232208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 232308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 232408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 232508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 232608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 232708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 232808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 232908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 233008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 233108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 233208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 2333339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 2334339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 2335339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 2336339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2337339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2338339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2339339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2340339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2341339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 23422e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 23432e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 23442e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 23452e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 23462e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 23472e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 23482b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); 23492e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 23502e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiControlService.PERMISSION); 23512e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 23520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2353