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 190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.Handler; 2102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport android.os.Looper; 224085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangimport android.os.MessageQueue; 23ece603b7955938d6001c376f351ca0a2219330acYuncheol Heoimport android.util.Slog; 247d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport android.util.SparseArray; 25e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 26959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport com.android.internal.util.Predicate; 28a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; 29a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 3002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport com.android.server.hdmi.HdmiControlService.DevicePollingCallback; 3102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 323f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jangimport libcore.util.EmptyArray; 333f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 347d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.ArrayList; 35b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jangimport java.util.LinkedList; 367d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.List; 370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command 400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * and pass it to CEC HAL so that it sends message to other device. For incoming 410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * message it translates the message and delegates it to proper module. 420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 4302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * <p>It should be careful to access member variables on IO thread because 4402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * it can be accessed from system thread as well. 4502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>It can be created only by {@link HdmiCecController#create} 470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only. 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 50a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangfinal class HdmiCecController { 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiCecController"; 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Interface to report allocated logical address. 553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang interface AllocateAddressCallback { 573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Called when a new logical address is allocated. 593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * 603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * @param deviceType requested device type to allocate logical address 613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * @param logicalAddress allocated logical address. If it is 6242230728b8212738c2351939c5577730f05a58deJungshik Jang * {@link Constants#ADDR_UNREGISTERED}, it means that 633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * it failed to allocate logical address for the given device type 643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void onAllocated(int deviceType, int logicalAddress); 663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 683f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private static final byte[] EMPTY_BODY = EmptyArray.BYTE; 693f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 703f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private static final int NUM_LOGICAL_ADDRESS = 16; 713f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 720f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Predicate for whether the given logical address is remote device's one or not. 730f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() { 740f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 750f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public boolean apply(Integer address) { 760f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return !isAllocatedLocalDeviceAddress(address); 770f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang }; 790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Predicate whether the given logical address is system audio's one or not 810f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() { 820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public boolean apply(Integer address) { 84c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM; 850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 860f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang }; 870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Handler instance to process synchronous I/O (mainly send) message. 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private Handler mIoHandler; 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Handler instance to process various messages coming from other CEC 920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // device or issued by internal state change. 93e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private Handler mControlHandler; 940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Stores the pointer to the native implementation of the service that 960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // interacts with HAL. 9702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private volatile long mNativePtr; 980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 997df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang private final HdmiControlService mService; 100a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 1017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // Stores the local CEC devices in the system. Device type is used for key. 1027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>(); 1037d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang 1040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Private constructor. Use HdmiCecController.create(). 1057df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang private HdmiCecController(HdmiControlService service) { 1067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang mService = service; 1070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang /** 1100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * A factory method to get {@link HdmiCecController}. If it fails to initialize 1110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * inner device or has no device it will return {@code null}. 1120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 1130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only. 114e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * @param service {@link HdmiControlService} instance used to create internal handler 115e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * and to pass callback for incoming message or event. 1160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, 1170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * returns {@code null}. 1180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 119e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang static HdmiCecController create(HdmiControlService service) { 1207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiCecController controller = new HdmiCecController(service); 1214085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue()); 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (nativePtr == 0L) { 1232918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim controller = null; 1240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang return null; 1250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang controller.init(nativePtr); 1282918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return controller; 1290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang private void init(long nativePtr) { 132f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mIoHandler = new Handler(mService.getIoLooper()); 1337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang mControlHandler = new Handler(mService.getServiceLooper()); 1342918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mNativePtr = nativePtr; 135a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } 136a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim 137a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void addLocalDevice(int deviceType, HdmiCecLocalDevice device) { 139a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 1403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mLocalDevices.put(deviceType, device); 1413f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 1423f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 1433f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang /** 1443f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * Allocate a new logical address of the given device type. Allocated 1453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * address will be reported through {@link AllocateAddressCallback}. 1463f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * 1473f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * <p> Declared as package-private, accessed by {@link HdmiControlService} only. 1483f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * 1493f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param deviceType type of device to used to determine logical address 1503f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param preferredAddress a logical address preferred to be allocated. 15142230728b8212738c2351939c5577730f05a58deJungshik Jang * If sets {@link Constants#ADDR_UNREGISTERED}, scans 1523f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * the smallest logical address matched with the given device type. 1533f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * Otherwise, scan address will start from {@code preferredAddress} 1543f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param callback callback interface to report allocated logical address to caller 1553f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang */ 156a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 157d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void allocateLogicalAddress(final int deviceType, final int preferredAddress, 1583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final AllocateAddressCallback callback) { 15902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 16002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 161d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnIoThread(new Runnable() { 162d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 163d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 164d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang handleAllocateLogicalAddress(deviceType, preferredAddress, callback); 165d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 166d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 167e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 168e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 169a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @IoThreadOnly 170d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress, 1713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final AllocateAddressCallback callback) { 17202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnIoThread(); 173d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang int startAddress = preferredAddress; 174d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // If preferred address is "unregistered", start address will be the smallest 175d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // address matched with the given device type. 176c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (preferredAddress == Constants.ADDR_UNREGISTERED) { 177d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { 178c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (deviceType == HdmiUtils.getTypeFromAddress(i)) { 179d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang startAddress = i; 180e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang break; 181d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 182e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 183e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 1843f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 185c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int logicalAddress = Constants.ADDR_UNREGISTERED; 186d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // Iterates all possible addresses which has the same device type. 187d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { 188d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS; 189c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (curAddress != Constants.ADDR_UNREGISTERED 190c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) { 1918e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang int failedPollingCount = 0; 1928e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) { 1938e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang if (!sendPollMessage(curAddress, curAddress, 1)) { 1948e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang failedPollingCount++; 1958e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang } 1968e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang } 1978e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang 1988e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang // Pick logical address if failed ratio is more than a half of all retries. 1998e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang if (failedPollingCount * 2 > HdmiConfig.ADDRESS_ALLOCATION_RETRY) { 200d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang logicalAddress = curAddress; 201d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang break; 2023f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 2033f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 204d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 2053f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 206d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang final int assignedAddress = logicalAddress; 2072e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("New logical address for device [%d]: [preferred:%d, assigned:%d]", 2082e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang deviceType, preferredAddress, assignedAddress); 209d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang if (callback != null) { 210d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnServiceThread(new Runnable() { 2118e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang @Override 212d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 213d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang callback.onAllocated(deviceType, assignedAddress); 2143f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 215d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 2163f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 217e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 218e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 219d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private static byte[] buildBody(int opcode, byte[] params) { 220d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang byte[] body = new byte[params.length + 1]; 221d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang body[0] = (byte) opcode; 222d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang System.arraycopy(params, 0, body, 1, params.length); 223d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang return body; 224e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 2250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2267d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] getPortInfos() { 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return nativeGetPortInfos(mNativePtr); 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 231a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 2327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * Return the locally hosted logical device of a given type. 2337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * 2347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * @param deviceType logical device type 2357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * @return {@link HdmiCecLocalDevice} instance if the instance of the type is available; 2367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * otherwise null. 2377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim */ 2387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice getLocalDevice(int deviceType) { 2397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return mLocalDevices.get(deviceType); 2407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 2417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 2427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim /** 243a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Add a new logical address to the device. Device's HW should be notified 244a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * when a new logical address is assigned to a device, so that it can accept 245a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * a command having available destinations. 246a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 247a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 248a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 249a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @param newLogicalAddress a logical address to be added 250a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @return 0 on success. Otherwise, returns negative value 251a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 252a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 253a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int addLogicalAddress(int newLogicalAddress) { 25402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 255c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (HdmiUtils.isValidAddress(newLogicalAddress)) { 256a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeAddLogicalAddress(mNativePtr, newLogicalAddress); 257a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } else { 258a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return -1; 259a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 260a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 261a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 262a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 263a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Clear all logical addresses registered in the device. 264a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 265a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 266a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 267a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 268a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang void clearLogicalAddress() { 26902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 2707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (int i = 0; i < mLocalDevices.size(); ++i) { 2717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim mLocalDevices.valueAt(i).clearAddress(); 2722918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 273a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang nativeClearLogicalAddress(mNativePtr); 274a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 275a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 2764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang void clearLocalDevices() { 2784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 2794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mLocalDevices.clear(); 2804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 282a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 283a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return the physical address of the device. 284a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 285a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 286a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 287a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @return CEC physical address of the device. The range of success address 288a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * is between 0x0000 and 0xFFFF. If failed it returns -1 289a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 290a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 291a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getPhysicalAddress() { 29202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 293a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetPhysicalAddress(mNativePtr); 294a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 295a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 296a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 297a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return CEC version of the device. 298a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 299a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 300a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 301a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 302a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getVersion() { 30302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 304a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetVersion(mNativePtr); 305a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 306a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 307a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 308a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return vendor id of the device. 309a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 310a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 311a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 312a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 313a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getVendorId() { 31402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 315a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetVendorId(mNativePtr); 316a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 317a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 31802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 319c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * Set an option to CEC HAL. 320092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 321c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param flag key of option 322c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param value value of option 323092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 324a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 325092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang void setOption(int flag, int value) { 326092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 327f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value); 328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang nativeSetOption(mNativePtr, flag, value); 329092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 330092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 331092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 332092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Configure ARC circuit in the hardware logic to start or stop the feature. 333092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 3341481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim * @param port ID of HDMI port to which AVR is connected 335092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param enabled whether to enable/disable ARC 336092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 337a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3381481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim void setAudioReturnChannel(int port, boolean enabled) { 339092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 3401481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim nativeSetAudioReturnChannel(mNativePtr, port, enabled); 341092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 342092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 343092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 344092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Return the connection status of the specified port 345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 346092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param port port number to check connection status 347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return true if connected; otherwise, return false 348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 349a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang boolean isConnected(int port) { 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return nativeIsConnected(mNativePtr, port); 353092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 354092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 355092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 35602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 35702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 35802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 35902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 36002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 36102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 3621de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 3630f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 36402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 36502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 366a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3671de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 3681de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 36902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 37002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 3710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Extract polling candidates. No need to poll against local devices. 3720f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang List<Integer> pollingCandidates = pickPollCandidates(pickStrategy); 373b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang ArrayList<Integer> allocated = new ArrayList<>(); 374b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang runDevicePolling(sourceAddress, pollingCandidates, retryCount, callback, allocated); 37502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 37602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 377cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang /** 378cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Return a list of all {@link HdmiCecLocalDevice}s. 379cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 380cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 381cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 382a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 383cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang List<HdmiCecLocalDevice> getLocalDeviceList() { 384cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang assertRunOnServiceThread(); 38579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return HdmiUtils.sparseArrayToList(mLocalDevices); 386cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 387cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 3880f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private List<Integer> pickPollCandidates(int pickStrategy) { 389c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 3900f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Predicate<Integer> pickPredicate = null; 3910f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang switch (strategy) { 392c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_STRATEGY_SYSTEM_AUDIO: 3930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pickPredicate = mSystemAudioAddressPredicate; 3940f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 395c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_STRATEGY_REMOTES_DEVICES: 3960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang default: // The default is POLL_STRATEGY_REMOTES_DEVICES. 3970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pickPredicate = mRemoteDeviceAddressPredicate; 3980f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 3990f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4000f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 401c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 402b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang LinkedList<Integer> pollingCandidates = new LinkedList<>(); 4030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang switch (iterationStrategy) { 404c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_ITERATION_IN_ORDER: 405c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) { 4060f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (pickPredicate.apply(i)) { 4070f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollingCandidates.add(i); 4080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4090f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 411c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_ITERATION_REVERSE_ORDER: 4120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang default: // The default is reverse order. 413c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) { 4140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (pickPredicate.apply(i)) { 4150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollingCandidates.add(i); 4160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4180f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 4190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return pollingCandidates; 4210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 423a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 42402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private boolean isAllocatedLocalDeviceAddress(int address) { 425a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (int i = 0; i < mLocalDevices.size(); ++i) { 4277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (mLocalDevices.valueAt(i).isAddressOf(address)) { 42802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return true; 42902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 43002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 43102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return false; 43202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 43302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 434a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4351de514256fd3015cf45256f3198ab5472024af9bJungshik Jang private void runDevicePolling(final int sourceAddress, 4361de514256fd3015cf45256f3198ab5472024af9bJungshik Jang final List<Integer> candidates, final int retryCount, 437b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang final DevicePollingCallback callback, final List<Integer> allocated) { 43802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 439b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang if (candidates.isEmpty()) { 440b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang if (callback != null) { 441b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang HdmiLogger.debug("[P]:AllocatedAddress=%s", allocated.toString()); 442b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang callback.onPollingFinished(allocated); 443b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang } 444b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang return; 445b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang } 446b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang 447b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang final Integer candidate = candidates.remove(0); 448b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang // Proceed polling action for the next address once polling action for the 449b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang // previous address is done. 45002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang runOnIoThread(new Runnable() { 45102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang @Override 45202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang public void run() { 453b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang if (sendPollMessage(sourceAddress, candidate, retryCount)) { 454b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang allocated.add(candidate); 45502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 456b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang runOnServiceThread(new Runnable() { 457b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang @Override 458b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang public void run() { 459b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang runDevicePolling(sourceAddress, candidates, retryCount, callback, 460b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang allocated); 461b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang } 462b3ecb72af8cbbd4f6f8089d0dc22289f6e2588f6Jungshik Jang }); 46302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang }); 46502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 467a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @IoThreadOnly 4681de514256fd3015cf45256f3198ab5472024af9bJungshik Jang private boolean sendPollMessage(int sourceAddress, int destinationAddress, int retryCount) { 46902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnIoThread(); 47002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang for (int i = 0; i < retryCount; ++i) { 4711de514256fd3015cf45256f3198ab5472024af9bJungshik Jang // <Polling Message> is a message which has empty body. 47202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // If sending <Polling Message> failed (NAK), it becomes 47302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // new logical address for the device because no device uses 47402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // it as logical address of the device. 4751de514256fd3015cf45256f3198ab5472024af9bJungshik Jang if (nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY) 476c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim == Constants.SEND_RESULT_SUCCESS) { 47702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return true; 47802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 47902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return false; 48102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 48302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private void assertRunOnIoThread() { 48402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang if (Looper.myLooper() != mIoHandler.getLooper()) { 48502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang throw new IllegalStateException("Should run on io thread."); 48602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 48902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private void assertRunOnServiceThread() { 49002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang if (Looper.myLooper() != mControlHandler.getLooper()) { 49102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang throw new IllegalStateException("Should run on service thread."); 49202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 49302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 49402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 49502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // Run a Runnable on IO thread. 49602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // It should be careful to access member variables on IO thread because 49702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // it can be accessed from system thread as well. 498d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void runOnIoThread(Runnable runnable) { 499d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mIoHandler.post(runnable); 500d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 501d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 502d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void runOnServiceThread(Runnable runnable) { 503d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mControlHandler.post(runnable); 504d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 505d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 506f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 507f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo void flush(final Runnable runnable) { 508f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo assertRunOnServiceThread(); 509f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo runOnIoThread(new Runnable() { 510f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 511f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 512f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // This ensures the runnable for cleanup is performed after all the pending 513f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // commands are processed by IO thread. 514f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo runOnServiceThread(runnable); 515f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 516f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 517f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 518f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 519a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private boolean isAcceptableAddress(int address) { 5202918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Can access command targeting devices available in local device or broadcast command. 521c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (address == Constants.ADDR_BROADCAST) { 5222918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return true; 5232918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 52402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return isAllocatedLocalDeviceAddress(address); 525a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 526a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 527a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 528e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private void onReceiveCommand(HdmiCecMessage message) { 52902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 5306aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo if (isAcceptableAddress(message.getDestination()) && mService.handleCecCommand(message)) { 531a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return; 532a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 5336aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // Not handled message, so we will reply it with <Feature Abort>. 5346aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE); 5356aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 5366aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 5376aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 5386aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage message, int reason) { 5396aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 5406aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // Swap the source and the destination. 5416aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo int src = message.getDestination(); 5426aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo int dest = message.getSource(); 5436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_UNREGISTERED) { 5446aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // Don't reply <Feature Abort> from the unregistered devices or for the broadcasted 5456aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // messages. See CEC 12.2 Protocol General Rules for detail. 5461827fdcbf6a53378f05620790e4798201341097bJungshik Jang return; 5473a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim } 5486aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo int originalOpcode = message.getOpcode(); 5496aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo if (originalOpcode == Constants.MESSAGE_FEATURE_ABORT) { 5501827fdcbf6a53378f05620790e4798201341097bJungshik Jang return; 5511827fdcbf6a53378f05620790e4798201341097bJungshik Jang } 5526aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo sendCommand( 5536aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo HdmiCecMessageBuilder.buildFeatureAbortCommand(src, dest, originalOpcode, reason)); 554a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 555e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 556a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5572918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim void sendCommand(HdmiCecMessage cecMessage) { 558a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5592918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim sendCommand(cecMessage, null); 5602918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 5612918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 562a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 563d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCommand(final HdmiCecMessage cecMessage, 564d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang final HdmiControlService.SendMessageCallback callback) { 565a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 566d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnIoThread(new Runnable() { 567d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 568d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 5692e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("[S]:" + cecMessage); 570d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); 5718ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang int i = 0; 5728ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang int errorCode = Constants.SEND_RESULT_SUCCESS; 5738ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang do { 5748ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(), 5758ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang cecMessage.getDestination(), body); 5768ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang if (errorCode == Constants.SEND_RESULT_SUCCESS) { 5778ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang break; 5788ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang } 5798ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang } while (i++ < HdmiConfig.RETRANSMISSION_COUNT); 5808ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang 5818ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang final int finalError = errorCode; 5828ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang if (finalError != Constants.SEND_RESULT_SUCCESS) { 583ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo Slog.w(TAG, "Failed to send " + cecMessage); 584ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo } 585d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang if (callback != null) { 586d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnServiceThread(new Runnable() { 587d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 588d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 5898ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang callback.onSendCompleted(finalError); 590d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 591d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 592d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 593d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 594d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 595e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 596e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 597e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 598e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Called by native when incoming CEC message arrived. 599e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 600a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 601e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { 6024085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang assertRunOnServiceThread(); 603c94ac5cffc982898bc4f7a5d97d8fad5520ff444Jungshik Jang HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body); 6042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("[R]:" + command); 605c94ac5cffc982898bc4f7a5d97d8fad5520ff444Jungshik Jang onReceiveCommand(command); 606e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 607e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 6080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang /** 609e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Called by native when a hotplug event issues. 6100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 61142230728b8212738c2351939c5577730f05a58deJungshik Jang @ServiceThreadOnly 61242230728b8212738c2351939c5577730f05a58deJungshik Jang private void handleHotplug(int port, boolean connected) { 61342230728b8212738c2351939c5577730f05a58deJungshik Jang assertRunOnServiceThread(); 6142e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected); 61542230728b8212738c2351939c5577730f05a58deJungshik Jang mService.onHotplug(port, connected); 6160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 6170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 618959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo void dump(final IndentingPrintWriter pw) { 619959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (int i = 0; i < mLocalDevices.size(); ++i) { 620959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("HdmiCecLocalDevice #" + i + ":"); 621959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 622959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mLocalDevices.valueAt(i).dump(pw); 623959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 624959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 625959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 626959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 6274085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); 628a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeSendCecCommand(long controllerPtr, int srcAddress, 629e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang int dstAddress, byte[] body); 630a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); 631a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native void nativeClearLogicalAddress(long controllerPtr); 632a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetPhysicalAddress(long controllerPtr); 633a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetVersion(long controllerPtr); 634a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetVendorId(long controllerPtr); 6350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); 636092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static native void nativeSetOption(long controllerPtr, int flag, int value); 6371481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim private static native void nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag); 638092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static native boolean nativeIsConnected(long controllerPtr, int port); 6390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 640