HdmiCecController.java revision 42230728b8212738c2351939c5577730f05a58de
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 260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jangimport com.android.internal.util.Predicate; 27a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; 28a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 2902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport com.android.server.hdmi.HdmiControlService.DevicePollingCallback; 3002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 313f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jangimport libcore.util.EmptyArray; 323f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 337d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.ArrayList; 347d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.List; 350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 360792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command 380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * and pass it to CEC HAL so that it sends message to other device. For incoming 390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * message it translates the message and delegates it to proper module. 400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 4102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * <p>It should be careful to access member variables on IO thread because 4202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * it can be accessed from system thread as well. 4302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>It can be created only by {@link HdmiCecController#create} 450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only. 470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 48a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangfinal class HdmiCecController { 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiCecController"; 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Interface to report allocated logical address. 533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang interface AllocateAddressCallback { 553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Called when a new logical address is allocated. 573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * 583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * @param deviceType requested device type to allocate logical address 593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * @param logicalAddress allocated logical address. If it is 6042230728b8212738c2351939c5577730f05a58deJungshik Jang * {@link Constants#ADDR_UNREGISTERED}, it means that 613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * it failed to allocate logical address for the given device type 623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void onAllocated(int deviceType, int logicalAddress); 643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 663f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private static final byte[] EMPTY_BODY = EmptyArray.BYTE; 673f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 68e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang // A message to pass cec send command to IO looper. 69e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private static final int MSG_SEND_CEC_COMMAND = 1; 703f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang // A message to delegate logical allocation to IO looper. 713f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2; 72e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 73e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang // Message types to handle incoming message in main service looper. 74e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private final static int MSG_RECEIVE_CEC_COMMAND = 1; 753f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang // A message to report allocated logical address to main control looper. 763f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private final static int MSG_REPORT_LOGICAL_ADDRESS = 2; 77e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 783f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang private static final int NUM_LOGICAL_ADDRESS = 16; 793f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 8002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private static final int RETRY_COUNT_FOR_LOGICAL_ADDRESS_ALLOCATION = 3; 8102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Predicate for whether the given logical address is remote device's one or not. 830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() { 840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public boolean apply(Integer address) { 860f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return !isAllocatedLocalDeviceAddress(address); 870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 880f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang }; 890f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 900f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Predicate whether the given logical address is system audio's one or not 910f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() { 920f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang @Override 930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang public boolean apply(Integer address) { 94c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM; 950f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang }; 970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Handler instance to process synchronous I/O (mainly send) message. 990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private Handler mIoHandler; 1000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Handler instance to process various messages coming from other CEC 1020792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // device or issued by internal state change. 103e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private Handler mControlHandler; 1040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Stores the pointer to the native implementation of the service that 1060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // interacts with HAL. 10702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private volatile long mNativePtr; 1080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 109a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private HdmiControlService mService; 110a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 1117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // Stores the local CEC devices in the system. Device type is used for key. 1127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>(); 1137d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang 1140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Private constructor. Use HdmiCecController.create(). 1150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController() { 1160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang /** 1190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * A factory method to get {@link HdmiCecController}. If it fails to initialize 1200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * inner device or has no device it will return {@code null}. 1210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only. 123e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * @param service {@link HdmiControlService} instance used to create internal handler 124e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * and to pass callback for incoming message or event. 1250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, 1260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * returns {@code null}. 1270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 128e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang static HdmiCecController create(HdmiControlService service) { 1292918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim HdmiCecController controller = new HdmiCecController(); 1304085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue()); 1310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (nativePtr == 0L) { 1322918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim controller = null; 1330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang return null; 1340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1362918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim controller.init(service, nativePtr); 1372918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return controller; 1380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim private void init(HdmiControlService service, long nativePtr) { 1412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mService = service; 1422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mIoHandler = new Handler(service.getServiceLooper()); 1432918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mControlHandler = new Handler(service.getServiceLooper()); 1442918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mNativePtr = nativePtr; 145a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } 146a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim 147a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void addLocalDevice(int deviceType, HdmiCecLocalDevice device) { 149a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 1503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mLocalDevices.put(deviceType, device); 1513f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 1523f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 1533f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang /** 1543f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * Allocate a new logical address of the given device type. Allocated 1553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * address will be reported through {@link AllocateAddressCallback}. 1563f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * 1573f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * <p> Declared as package-private, accessed by {@link HdmiControlService} only. 1583f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * 1593f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param deviceType type of device to used to determine logical address 1603f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param preferredAddress a logical address preferred to be allocated. 16142230728b8212738c2351939c5577730f05a58deJungshik Jang * If sets {@link Constants#ADDR_UNREGISTERED}, scans 1623f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * the smallest logical address matched with the given device type. 1633f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * Otherwise, scan address will start from {@code preferredAddress} 1643f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang * @param callback callback interface to report allocated logical address to caller 1653f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang */ 166a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 167d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void allocateLogicalAddress(final int deviceType, final int preferredAddress, 1683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final AllocateAddressCallback callback) { 16902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 17002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 171d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnIoThread(new Runnable() { 172d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 173d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 174d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang handleAllocateLogicalAddress(deviceType, preferredAddress, callback); 175d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 176d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 177e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 178e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 179a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @IoThreadOnly 180d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress, 1813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final AllocateAddressCallback callback) { 18202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnIoThread(); 183d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang int startAddress = preferredAddress; 184d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // If preferred address is "unregistered", start address will be the smallest 185d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // address matched with the given device type. 186c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (preferredAddress == Constants.ADDR_UNREGISTERED) { 187d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { 188c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (deviceType == HdmiUtils.getTypeFromAddress(i)) { 189d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang startAddress = i; 190e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang break; 191d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 192e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 193e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 1943f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 195c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int logicalAddress = Constants.ADDR_UNREGISTERED; 196d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang // Iterates all possible addresses which has the same device type. 197d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { 198d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS; 199c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (curAddress != Constants.ADDR_UNREGISTERED 200c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) { 2011de514256fd3015cf45256f3198ab5472024af9bJungshik Jang if (!sendPollMessage(curAddress, curAddress, 2021de514256fd3015cf45256f3198ab5472024af9bJungshik Jang RETRY_COUNT_FOR_LOGICAL_ADDRESS_ALLOCATION)) { 203d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang logicalAddress = curAddress; 204d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang break; 2053f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 2063f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 207d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 2083f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang 209d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang final int assignedAddress = logicalAddress; 210d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang if (callback != null) { 211d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnServiceThread(new Runnable() { 212d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 213d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 214d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang callback.onAllocated(deviceType, assignedAddress); 2153f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 216d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 2173f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang } 218e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 219e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 220d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private static byte[] buildBody(int opcode, byte[] params) { 221d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang byte[] body = new byte[params.length + 1]; 222d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang body[0] = (byte) opcode; 223d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang System.arraycopy(params, 0, body, 1, params.length); 224d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang return body; 225e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 2260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2277d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] getPortInfos() { 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return nativeGetPortInfos(mNativePtr); 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 232a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 2337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * Return the locally hosted logical device of a given type. 2347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * 2357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * @param deviceType logical device type 2367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * @return {@link HdmiCecLocalDevice} instance if the instance of the type is available; 2377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim * otherwise null. 2387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim */ 2397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice getLocalDevice(int deviceType) { 2407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return mLocalDevices.get(deviceType); 2417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 2427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 2437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim /** 244a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Add a new logical address to the device. Device's HW should be notified 245a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * when a new logical address is assigned to a device, so that it can accept 246a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * a command having available destinations. 247a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 248a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 249a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 250a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @param newLogicalAddress a logical address to be added 251a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @return 0 on success. Otherwise, returns negative value 252a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 253a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 254a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int addLogicalAddress(int newLogicalAddress) { 25502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 256c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (HdmiUtils.isValidAddress(newLogicalAddress)) { 257a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeAddLogicalAddress(mNativePtr, newLogicalAddress); 258a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } else { 259a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return -1; 260a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 261a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 262a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 263a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 264a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Clear all logical addresses registered in the device. 265a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 266a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 267a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 268a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 269a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang void clearLogicalAddress() { 27002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 271a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // TODO: consider to backup logical address so that new logical address 272a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // allocation can use it as preferred address. 2737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (int i = 0; i < mLocalDevices.size(); ++i) { 2747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim mLocalDevices.valueAt(i).clearAddress(); 2752918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 276a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang nativeClearLogicalAddress(mNativePtr); 277a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 278a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 279a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 280a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return the physical address of the device. 281a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 282a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 283a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 284a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * @return CEC physical address of the device. The range of success address 285a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * is between 0x0000 and 0xFFFF. If failed it returns -1 286a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 287a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 288a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getPhysicalAddress() { 28902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 290a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetPhysicalAddress(mNativePtr); 291a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 292a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 293a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 294a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return CEC version of the device. 295a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 296a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 297a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 298a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 299a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getVersion() { 30002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 301a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetVersion(mNativePtr); 302a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 303a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 304a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang /** 305a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * Return vendor id of the device. 306a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * 307a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 308a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang */ 309a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 310a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang int getVendorId() { 31102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 312a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang return nativeGetVendorId(mNativePtr); 313a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang } 314a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang 31502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 316c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * Set an option to CEC HAL. 317092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 318c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param flag key of option 319c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim * @param value value of option 320092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 321a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 322092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang void setOption(int flag, int value) { 323092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 324092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang nativeSetOption(mNativePtr, flag, value); 325092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 326092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 327092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Configure ARC circuit in the hardware logic to start or stop the feature. 329092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 330092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param enabled whether to enable/disable ARC 331092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 332a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 333092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang void setAudioReturnChannel(boolean enabled) { 334092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 335092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang nativeSetAudioReturnChannel(mNativePtr, enabled); 336092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 337092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 338092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 339092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Return the connection status of the specified port 340092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 341092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param port port number to check connection status 342092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return true if connected; otherwise, return false 343092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 344a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang boolean isConnected(int port) { 346092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang assertRunOnServiceThread(); 347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return nativeIsConnected(mNativePtr, port); 348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 35102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 35202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 35302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 35402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 35502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 35602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 3571de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 3580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 35902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 36002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 361a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3621de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 3631de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 36402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 36502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 3660f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang // Extract polling candidates. No need to poll against local devices. 3670f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang List<Integer> pollingCandidates = pickPollCandidates(pickStrategy); 3681de514256fd3015cf45256f3198ab5472024af9bJungshik Jang runDevicePolling(sourceAddress, pollingCandidates, retryCount, callback); 36902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 37002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 371cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang /** 372cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Return a list of all {@link HdmiCecLocalDevice}s. 373cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 374cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 375cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 376a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 377cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang List<HdmiCecLocalDevice> getLocalDeviceList() { 378cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang assertRunOnServiceThread(); 37979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return HdmiUtils.sparseArrayToList(mLocalDevices); 380cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 381cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 3820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private List<Integer> pickPollCandidates(int pickStrategy) { 383c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 3840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang Predicate<Integer> pickPredicate = null; 3850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang switch (strategy) { 386c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_STRATEGY_SYSTEM_AUDIO: 3870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pickPredicate = mSystemAudioAddressPredicate; 3880f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 389c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_STRATEGY_REMOTES_DEVICES: 3900f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang default: // The default is POLL_STRATEGY_REMOTES_DEVICES. 3910f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pickPredicate = mRemoteDeviceAddressPredicate; 3920f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 3930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 3940f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 395c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 3960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang ArrayList<Integer> pollingCandidates = new ArrayList<>(); 3970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang switch (iterationStrategy) { 398c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_ITERATION_IN_ORDER: 399c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) { 4000f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (pickPredicate.apply(i)) { 4010f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollingCandidates.add(i); 4020f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4040f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 405c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.POLL_ITERATION_REVERSE_ORDER: 4060f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang default: // The default is reverse order. 407c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) { 4080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (pickPredicate.apply(i)) { 4090f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang pollingCandidates.add(i); 4100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang break; 4130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return pollingCandidates; 4150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 417a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 41802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private boolean isAllocatedLocalDeviceAddress(int address) { 419a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (int i = 0; i < mLocalDevices.size(); ++i) { 4217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (mLocalDevices.valueAt(i).isAddressOf(address)) { 42202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return true; 42302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 42402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 42502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return false; 42602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 42702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 428a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4291de514256fd3015cf45256f3198ab5472024af9bJungshik Jang private void runDevicePolling(final int sourceAddress, 4301de514256fd3015cf45256f3198ab5472024af9bJungshik Jang final List<Integer> candidates, final int retryCount, 43102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang final DevicePollingCallback callback) { 43202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 43302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang runOnIoThread(new Runnable() { 43402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang @Override 43502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang public void run() { 43602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang final ArrayList<Integer> allocated = new ArrayList<>(); 43702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang for (Integer address : candidates) { 4381de514256fd3015cf45256f3198ab5472024af9bJungshik Jang if (sendPollMessage(sourceAddress, address, retryCount)) { 43902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang allocated.add(address); 44002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 44102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 44202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang if (callback != null) { 44302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang runOnServiceThread(new Runnable() { 44402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang @Override 44502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang public void run() { 44602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang callback.onPollingFinished(allocated); 44702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 44802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang }); 44902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 45002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 45102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang }); 45202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 45302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 454a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @IoThreadOnly 4551de514256fd3015cf45256f3198ab5472024af9bJungshik Jang private boolean sendPollMessage(int sourceAddress, int destinationAddress, int retryCount) { 45602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnIoThread(); 45702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang for (int i = 0; i < retryCount; ++i) { 4581de514256fd3015cf45256f3198ab5472024af9bJungshik Jang // <Polling Message> is a message which has empty body. 45902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // If sending <Polling Message> failed (NAK), it becomes 46002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // new logical address for the device because no device uses 46102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // it as logical address of the device. 4621de514256fd3015cf45256f3198ab5472024af9bJungshik Jang if (nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY) 463c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim == Constants.SEND_RESULT_SUCCESS) { 46402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return true; 46502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return false; 46802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 47002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private void assertRunOnIoThread() { 47102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang if (Looper.myLooper() != mIoHandler.getLooper()) { 47202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang throw new IllegalStateException("Should run on io thread."); 47302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 47402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 47502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 47602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang private void assertRunOnServiceThread() { 47702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang if (Looper.myLooper() != mControlHandler.getLooper()) { 47802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang throw new IllegalStateException("Should run on service thread."); 47902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 48102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 48202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // Run a Runnable on IO thread. 48302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // It should be careful to access member variables on IO thread because 48402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang // it can be accessed from system thread as well. 485d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void runOnIoThread(Runnable runnable) { 486d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mIoHandler.post(runnable); 487d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 488d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 489d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang private void runOnServiceThread(Runnable runnable) { 490d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mControlHandler.post(runnable); 491d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 492d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 493a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private boolean isAcceptableAddress(int address) { 4942918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Can access command targeting devices available in local device or broadcast command. 495c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (address == Constants.ADDR_BROADCAST) { 4962918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return true; 4972918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 49802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang return isAllocatedLocalDeviceAddress(address); 499a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 500a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 501a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 502e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private void onReceiveCommand(HdmiCecMessage message) { 50302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang assertRunOnServiceThread(); 5044085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang if (isAcceptableAddress(message.getDestination()) 5054085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang && mService.handleCecCommand(message)) { 506a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return; 507a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 508e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 509c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 5103a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim int sourceAddress = message.getDestination(); 5113a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim // Reply <Feature Abort> to initiator (source) for all requests. 5123a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( 5133a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim sourceAddress, message.getSource(), message.getOpcode(), 514c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim Constants.ABORT_REFUSED); 515a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang sendCommand(cecMessage); 5163a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim } 517a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 518e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 519a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5202918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim void sendCommand(HdmiCecMessage cecMessage) { 521a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5222918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim sendCommand(cecMessage, null); 5232918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 5242918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 525a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 526d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCommand(final HdmiCecMessage cecMessage, 527d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang final HdmiControlService.SendMessageCallback callback) { 528a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 529d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnIoThread(new Runnable() { 530d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 531d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 532d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); 533d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(), 534d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang cecMessage.getDestination(), body); 535c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (error != Constants.SEND_RESULT_SUCCESS) { 536ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo Slog.w(TAG, "Failed to send " + cecMessage); 537ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo } 538d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang if (callback != null) { 539d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang runOnServiceThread(new Runnable() { 540d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang @Override 541d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang public void run() { 542d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang callback.onSendCompleted(error); 543d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 544d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 545d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 546d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 547d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang }); 548e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 549e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 550e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 551e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Called by native when incoming CEC message arrived. 552e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 553a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 554e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { 5554085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang assertRunOnServiceThread(); 5564085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang onReceiveCommand(HdmiCecMessageBuilder.of(srcAddress, dstAddress, body)); 557e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 558e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 5590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang /** 560e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Called by native when a hotplug event issues. 5610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 56242230728b8212738c2351939c5577730f05a58deJungshik Jang @ServiceThreadOnly 56342230728b8212738c2351939c5577730f05a58deJungshik Jang private void handleHotplug(int port, boolean connected) { 56442230728b8212738c2351939c5577730f05a58deJungshik Jang assertRunOnServiceThread(); 56542230728b8212738c2351939c5577730f05a58deJungshik Jang mService.onHotplug(port, connected); 5660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 5670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5684085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); 569a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeSendCecCommand(long controllerPtr, int srcAddress, 570e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang int dstAddress, byte[] body); 571a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); 572a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native void nativeClearLogicalAddress(long controllerPtr); 573a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetPhysicalAddress(long controllerPtr); 574a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetVersion(long controllerPtr); 575a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang private static native int nativeGetVendorId(long controllerPtr); 5760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); 577092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static native void nativeSetOption(long controllerPtr, int flag, int value); 578092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag); 579092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static native boolean nativeIsConnected(long controllerPtr, int port); 5800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 581