HdmiCecController.java revision 2e8f1b6399089626b4f0249427626ba6e63a62ef
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;
357d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.List;
360792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/**
380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * and pass it to CEC HAL so that it sends message to other device. For incoming
400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * message it translates the message and delegates it to proper module.
410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
4202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * <p>It should be careful to access member variables on IO thread because
4302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * it can be accessed from system thread as well.
4402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang *
450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>It can be created only by {@link HdmiCecController#create}
460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */
49a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangfinal class HdmiCecController {
500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private static final String TAG = "HdmiCecController";
510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    /**
533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang     * Interface to report allocated logical address.
543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang     */
553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    interface AllocateAddressCallback {
563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        /**
573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         * Called when a new logical address is allocated.
583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         *
593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         * @param deviceType requested device type to allocate logical address
603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         * @param logicalAddress allocated logical address. If it is
6142230728b8212738c2351939c5577730f05a58deJungshik Jang         *                       {@link Constants#ADDR_UNREGISTERED}, it means that
623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         *                       it failed to allocate logical address for the given device type
633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang         */
643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        void onAllocated(int deviceType, int logicalAddress);
653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    }
663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang
673f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang    private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
683f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang
693f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang    private static final int NUM_LOGICAL_ADDRESS = 16;
703f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang
710f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    // Predicate for whether the given logical address is remote device's one or not.
720f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
730f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        @Override
740f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        public boolean apply(Integer address) {
750f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang            return !isAllocatedLocalDeviceAddress(address);
760f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        }
770f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    };
780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang
790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    // Predicate whether the given logical address is system audio's one or not
800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() {
810f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        @Override
820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        public boolean apply(Integer address) {
83c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM;
840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        }
850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    };
860f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang
870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Handler instance to process synchronous I/O (mainly send) message.
880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private Handler mIoHandler;
890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Handler instance to process various messages coming from other CEC
910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // device or issued by internal state change.
92e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private Handler mControlHandler;
930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Stores the pointer to the native implementation of the service that
950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // interacts with HAL.
9602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    private volatile long mNativePtr;
970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang    private final HdmiControlService mService;
99a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang
1007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim    // Stores the local CEC devices in the system. Device type is used for key.
1017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim    private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
1027d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
1030792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Private constructor.  Use HdmiCecController.create().
1047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang    private HdmiCecController(HdmiControlService service) {
1057df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang        mService = service;
1060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
1070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /**
1090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * A factory method to get {@link HdmiCecController}. If it fails to initialize
1100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * inner device or has no device it will return {@code null}.
1110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     *
1120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
113e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * @param service {@link HdmiControlService} instance used to create internal handler
114e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     *                and to pass callback for incoming message or event.
1150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
1160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     *         returns {@code null}.
1170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     */
118e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    static HdmiCecController create(HdmiControlService service) {
1197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang        HdmiCecController controller = new HdmiCecController(service);
1204085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue());
1210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        if (nativePtr == 0L) {
1222918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim            controller = null;
1230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang            return null;
1240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        }
1250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang        controller.init(nativePtr);
1272918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        return controller;
1280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
1290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang    private void init(long nativePtr) {
1317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang        mIoHandler = new Handler(mService.getServiceLooper());
1327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang        mControlHandler = new Handler(mService.getServiceLooper());
1332918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mNativePtr = nativePtr;
134a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim    }
135a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim
136a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
1373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    void addLocalDevice(int deviceType, HdmiCecLocalDevice device) {
138a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
1393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mLocalDevices.put(deviceType, device);
1403f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang    }
1413f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang
1423f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang    /**
1433f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     * Allocate a new logical address of the given device type. Allocated
1443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang     * address will be reported through {@link AllocateAddressCallback}.
1453f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     *
1463f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     * <p> Declared as package-private, accessed by {@link HdmiControlService} only.
1473f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     *
1483f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     * @param deviceType type of device to used to determine logical address
1493f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     * @param preferredAddress a logical address preferred to be allocated.
15042230728b8212738c2351939c5577730f05a58deJungshik Jang     *                         If sets {@link Constants#ADDR_UNREGISTERED}, scans
1513f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     *                         the smallest logical address matched with the given device type.
1523f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     *                         Otherwise, scan address will start from {@code preferredAddress}
1533f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     * @param callback callback interface to report allocated logical address to caller
1543f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang     */
155a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
156d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    void allocateLogicalAddress(final int deviceType, final int preferredAddress,
1573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            final AllocateAddressCallback callback) {
15802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
15902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
160d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        runOnIoThread(new Runnable() {
161d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            @Override
162d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            public void run() {
163d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
164d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            }
165d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        });
166e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
167e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
168a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @IoThreadOnly
169d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress,
1703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            final AllocateAddressCallback callback) {
17102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnIoThread();
172d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        int startAddress = preferredAddress;
173d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        // If preferred address is "unregistered", start address will be the smallest
174d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        // address matched with the given device type.
175c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        if (preferredAddress == Constants.ADDR_UNREGISTERED) {
176d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
177c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                if (deviceType == HdmiUtils.getTypeFromAddress(i)) {
178d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    startAddress = i;
179e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    break;
180d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                }
181e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            }
182e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        }
1833f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang
184c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        int logicalAddress = Constants.ADDR_UNREGISTERED;
185d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        // Iterates all possible addresses which has the same device type.
186d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
187d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
188c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            if (curAddress != Constants.ADDR_UNREGISTERED
189c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
1908e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                int failedPollingCount = 0;
1918e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
1928e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                    if (!sendPollMessage(curAddress, curAddress, 1)) {
1938e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                        failedPollingCount++;
1948e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                    }
1958e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                }
1968e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang
1978e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                // Pick logical address if failed ratio is more than a half of all retries.
1988e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                if (failedPollingCount * 2 >  HdmiConfig.ADDRESS_ALLOCATION_RETRY) {
199d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    logicalAddress = curAddress;
200d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    break;
2013f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang                }
2023f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang            }
203d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        }
2043f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang
205d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        final int assignedAddress = logicalAddress;
2062e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang        HdmiLogger.debug("New logical address for device [%d]: [preferred:%d, assigned:%d]",
2072e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang                        deviceType, preferredAddress, assignedAddress);
208d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        if (callback != null) {
209d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            runOnServiceThread(new Runnable() {
2108e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang                @Override
211d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                public void run() {
212d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    callback.onAllocated(deviceType, assignedAddress);
2133f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang                }
214d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            });
2153f74ab0ee0ec27a6be31cdb5a4258f4f25909ba8Jungshik Jang        }
216e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
217e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
218d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    private static byte[] buildBody(int opcode, byte[] params) {
219d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        byte[] body = new byte[params.length + 1];
220d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        body[0] = (byte) opcode;
221d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        System.arraycopy(params, 0, body, 1, params.length);
222d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        return body;
223e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
2240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
2257d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    HdmiPortInfo[] getPortInfos() {
2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return nativeGetPortInfos(mNativePtr);
2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
230a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    /**
2317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     * Return the locally hosted logical device of a given type.
2327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     *
2337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     * @param deviceType logical device type
2347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     * @return {@link HdmiCecLocalDevice} instance if the instance of the type is available;
2357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     *          otherwise null.
2367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim     */
2377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim    HdmiCecLocalDevice getLocalDevice(int deviceType) {
2387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim        return mLocalDevices.get(deviceType);
2397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim    }
2407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim
2417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim    /**
242a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * Add a new logical address to the device. Device's HW should be notified
243a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * when a new logical address is assigned to a device, so that it can accept
244a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * a command having available destinations.
245a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
246a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
247a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
248a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * @param newLogicalAddress a logical address to be added
249a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * @return 0 on success. Otherwise, returns negative value
250a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     */
251a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
252a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int addLogicalAddress(int newLogicalAddress) {
25302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
254c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        if (HdmiUtils.isValidAddress(newLogicalAddress)) {
255a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang            return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
256a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        } else {
257a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang            return -1;
258a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        }
259a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
260a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
261a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    /**
262a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * Clear all logical addresses registered in the device.
263a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
264a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
265a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     */
266a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
267a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    void clearLogicalAddress() {
26802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
2697fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim        for (int i = 0; i < mLocalDevices.size(); ++i) {
2707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim            mLocalDevices.valueAt(i).clearAddress();
2712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        }
272a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        nativeClearLogicalAddress(mNativePtr);
273a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
274a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
2754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    @ServiceThreadOnly
2764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    void clearLocalDevices() {
2774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        assertRunOnServiceThread();
2784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        mLocalDevices.clear();
2794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    }
2804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
281a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    /**
282a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * Return the physical address of the device.
283a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
284a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
285a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
286a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * @return CEC physical address of the device. The range of success address
287a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *         is between 0x0000 and 0xFFFF. If failed it returns -1
288a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     */
289a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
290a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getPhysicalAddress() {
29102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
292a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        return nativeGetPhysicalAddress(mNativePtr);
293a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
294a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
295a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    /**
296a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * Return CEC version of the device.
297a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
298a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
299a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     */
300a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
301a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getVersion() {
30202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
303a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        return nativeGetVersion(mNativePtr);
304a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
305a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
306a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    /**
307a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * Return vendor id of the device.
308a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     *
309a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
310a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang     */
311a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
312a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getVendorId() {
31302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
314a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang        return nativeGetVendorId(mNativePtr);
315a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
316a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
31702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    /**
318c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim     * Set an option to CEC HAL.
319092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
320c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim     * @param flag key of option
321c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim     * @param value value of option
322092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
323a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
324092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    void setOption(int flag, int value) {
325092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        assertRunOnServiceThread();
326092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        nativeSetOption(mNativePtr, flag, value);
327092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
329092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
330092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Configure ARC circuit in the hardware logic to start or stop the feature.
331092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
332092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param enabled whether to enable/disable ARC
333092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
334a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
335092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    void setAudioReturnChannel(boolean enabled) {
336092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        assertRunOnServiceThread();
337092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        nativeSetAudioReturnChannel(mNativePtr, enabled);
338092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
339092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
340092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
341092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Return the connection status of the specified port
342092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
343092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param port port number to check connection status
344092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @return true if connected; otherwise, return false
345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
346a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    boolean isConnected(int port) {
348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        assertRunOnServiceThread();
349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return nativeIsConnected(mNativePtr, port);
350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
35302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     * Poll all remote devices. It sends &lt;Polling Message&gt; to all remote
35402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     * devices.
35502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     *
35602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
35702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     *
35802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     * @param callback an interface used to get a list of all remote devices' address
3591de514256fd3015cf45256f3198ab5472024af9bJungshik Jang     * @param sourceAddress a logical address of source device where sends polling message
3600f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang     * @param pickStrategy strategy how to pick polling candidates
36102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     * @param retryCount the number of retry used to send polling message to remote devices
36202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang     */
363a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
3641de514256fd3015cf45256f3198ab5472024af9bJungshik Jang    void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy,
3651de514256fd3015cf45256f3198ab5472024af9bJungshik Jang            int retryCount) {
36602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
36702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
3680f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        // Extract polling candidates. No need to poll against local devices.
3690f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        List<Integer> pollingCandidates = pickPollCandidates(pickStrategy);
3701de514256fd3015cf45256f3198ab5472024af9bJungshik Jang        runDevicePolling(sourceAddress, pollingCandidates, retryCount, callback);
37102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
37202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
373cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang    /**
374cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang     * Return a list of all {@link HdmiCecLocalDevice}s.
375cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang     *
376cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
377cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang     */
378a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
379cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang    List<HdmiCecLocalDevice> getLocalDeviceList() {
380cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang        assertRunOnServiceThread();
38179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return HdmiUtils.sparseArrayToList(mLocalDevices);
382cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang    }
383cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang
3840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    private List<Integer> pickPollCandidates(int pickStrategy) {
385c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK;
3860f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        Predicate<Integer> pickPredicate = null;
3870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        switch (strategy) {
388c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.POLL_STRATEGY_SYSTEM_AUDIO:
3890f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                pickPredicate = mSystemAudioAddressPredicate;
3900f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                break;
391c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.POLL_STRATEGY_REMOTES_DEVICES:
3920f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang            default:  // The default is POLL_STRATEGY_REMOTES_DEVICES.
3930f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                pickPredicate = mRemoteDeviceAddressPredicate;
3940f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                break;
3950f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        }
3960f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang
397c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK;
3980f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        ArrayList<Integer> pollingCandidates = new ArrayList<>();
3990f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        switch (iterationStrategy) {
400c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.POLL_ITERATION_IN_ORDER:
401c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) {
4020f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                    if (pickPredicate.apply(i)) {
4030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                        pollingCandidates.add(i);
4040f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                    }
4050f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                }
4060f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                break;
407c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.POLL_ITERATION_REVERSE_ORDER:
4080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang            default:  // The default is reverse order.
409c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) {
4100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                    if (pickPredicate.apply(i)) {
4110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                        pollingCandidates.add(i);
4120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                    }
4130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                }
4140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang                break;
4150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        }
4160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang        return pollingCandidates;
4170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang    }
4180f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang
419a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
42002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    private boolean isAllocatedLocalDeviceAddress(int address) {
421a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
4227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim        for (int i = 0; i < mLocalDevices.size(); ++i) {
4237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim            if (mLocalDevices.valueAt(i).isAddressOf(address)) {
42402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                return true;
42502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            }
42602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        }
42702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        return false;
42802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
42902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
430a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
4311de514256fd3015cf45256f3198ab5472024af9bJungshik Jang    private void runDevicePolling(final int sourceAddress,
4321de514256fd3015cf45256f3198ab5472024af9bJungshik Jang            final List<Integer> candidates, final int retryCount,
43302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            final DevicePollingCallback callback) {
43402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
43502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        runOnIoThread(new Runnable() {
43602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            @Override
43702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            public void run() {
43802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                final ArrayList<Integer> allocated = new ArrayList<>();
43902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                for (Integer address : candidates) {
4401de514256fd3015cf45256f3198ab5472024af9bJungshik Jang                    if (sendPollMessage(sourceAddress, address, retryCount)) {
44102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                        allocated.add(address);
44202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                    }
44302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                }
4442e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang                HdmiLogger.debug("[P]:Allocated Address=" + allocated);
44502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                if (callback != null) {
44602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                    runOnServiceThread(new Runnable() {
44702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                        @Override
44802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                        public void run() {
44902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                            callback.onPollingFinished(allocated);
45002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                        }
45102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                    });
45202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                }
45302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            }
45402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        });
45502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
45602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
457a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @IoThreadOnly
4581de514256fd3015cf45256f3198ab5472024af9bJungshik Jang    private boolean sendPollMessage(int sourceAddress, int destinationAddress, int retryCount) {
45902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnIoThread();
46002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        for (int i = 0; i < retryCount; ++i) {
4611de514256fd3015cf45256f3198ab5472024af9bJungshik Jang            // <Polling Message> is a message which has empty body.
46202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            // If sending <Polling Message> failed (NAK), it becomes
46302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            // new logical address for the device because no device uses
46402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            // it as logical address of the device.
4651de514256fd3015cf45256f3198ab5472024af9bJungshik Jang            if (nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY)
466c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                    == Constants.SEND_RESULT_SUCCESS) {
46702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang                return true;
46802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            }
46902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        }
47002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        return false;
47102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
47202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
47302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    private void assertRunOnIoThread() {
47402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        if (Looper.myLooper() != mIoHandler.getLooper()) {
47502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            throw new IllegalStateException("Should run on io thread.");
47602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        }
47702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
47802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
47902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    private void assertRunOnServiceThread() {
48002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        if (Looper.myLooper() != mControlHandler.getLooper()) {
48102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang            throw new IllegalStateException("Should run on service thread.");
48202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        }
48302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    }
48402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang
48502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    // Run a Runnable on IO thread.
48602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    // It should be careful to access member variables on IO thread because
48702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang    // it can be accessed from system thread as well.
488d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    private void runOnIoThread(Runnable runnable) {
489d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mIoHandler.post(runnable);
490d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
491d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
492d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    private void runOnServiceThread(Runnable runnable) {
493d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mControlHandler.post(runnable);
494d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
495d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
496a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang    private boolean isAcceptableAddress(int address) {
4972918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        // Can access command targeting devices available in local device or broadcast command.
498c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        if (address == Constants.ADDR_BROADCAST) {
4992918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim            return true;
5002918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        }
50102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        return isAllocatedLocalDeviceAddress(address);
502a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang    }
503a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang
504a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
505e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void onReceiveCommand(HdmiCecMessage message) {
50602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang        assertRunOnServiceThread();
5076aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        if (isAcceptableAddress(message.getDestination()) && mService.handleCecCommand(message)) {
508a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang            return;
509a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang        }
5106aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        // Not handled message, so we will reply it with <Feature Abort>.
5116aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
5126aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo    }
5136aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo
5146aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo    @ServiceThreadOnly
5156aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo    void maySendFeatureAbortCommand(HdmiCecMessage message, int reason) {
5166aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        assertRunOnServiceThread();
5176aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        // Swap the source and the destination.
5186aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        int src = message.getDestination();
5196aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        int dest = message.getSource();
5206aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_UNREGISTERED) {
5216aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo            // Don't reply <Feature Abort> from the unregistered devices or for the broadcasted
5226aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo            // messages. See CEC 12.2 Protocol General Rules for detail.
5231827fdcbf6a53378f05620790e4798201341097bJungshik Jang            return;
5243a2f74373a6892ca5c11cd19b4b662c069634717Jinsuk Kim        }
5256aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        int originalOpcode = message.getOpcode();
5266aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        if (originalOpcode == Constants.MESSAGE_FEATURE_ABORT) {
5271827fdcbf6a53378f05620790e4798201341097bJungshik Jang            return;
5281827fdcbf6a53378f05620790e4798201341097bJungshik Jang        }
5296aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo        sendCommand(
5306aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo                HdmiCecMessageBuilder.buildFeatureAbortCommand(src, dest, originalOpcode, reason));
531a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang    }
532e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
533a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
5342918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    void sendCommand(HdmiCecMessage cecMessage) {
535a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
5362918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        sendCommand(cecMessage, null);
5372918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
5382918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
539a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
540d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    void sendCommand(final HdmiCecMessage cecMessage,
541d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            final HdmiControlService.SendMessageCallback callback) {
542a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
543d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        runOnIoThread(new Runnable() {
544d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            @Override
545d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            public void run() {
5462e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang                HdmiLogger.debug("[S]:" + cecMessage);
547d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
5488ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                int i = 0;
5498ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                int errorCode = Constants.SEND_RESULT_SUCCESS;
5508ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                do {
5518ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                    errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
5528ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                            cecMessage.getDestination(), body);
5538ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                    if (errorCode == Constants.SEND_RESULT_SUCCESS) {
5548ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                        break;
5558ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                    }
5568ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                } while (i++ < HdmiConfig.RETRANSMISSION_COUNT);
5578ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang
5588ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                final int finalError = errorCode;
5598ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                if (finalError != Constants.SEND_RESULT_SUCCESS) {
560ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo                    Slog.w(TAG, "Failed to send " + cecMessage);
561ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo                }
562d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                if (callback != null) {
563d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    runOnServiceThread(new Runnable() {
564d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                        @Override
565d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                        public void run() {
5668ed86c467afa107f7aafacb85ca64c979cf56dc2Jungshik Jang                            callback.onSendCompleted(finalError);
567d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                        }
568d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                    });
569d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                }
570d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            }
571d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        });
572e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
573e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
574e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    /**
575e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * Called by native when incoming CEC message arrived.
576e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     */
577a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
578e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
5794085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        assertRunOnServiceThread();
580c94ac5cffc982898bc4f7a5d97d8fad5520ff444Jungshik Jang        HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
5812e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang        HdmiLogger.debug("[R]:" + command);
582c94ac5cffc982898bc4f7a5d97d8fad5520ff444Jungshik Jang        onReceiveCommand(command);
583e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
584e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
5850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /**
586e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * Called by native when a hotplug event issues.
5870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     */
58842230728b8212738c2351939c5577730f05a58deJungshik Jang    @ServiceThreadOnly
58942230728b8212738c2351939c5577730f05a58deJungshik Jang    private void handleHotplug(int port, boolean connected) {
59042230728b8212738c2351939c5577730f05a58deJungshik Jang        assertRunOnServiceThread();
5912e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang        HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected);
59242230728b8212738c2351939c5577730f05a58deJungshik Jang        mService.onHotplug(port, connected);
5930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
5940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
595959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo    void dump(final IndentingPrintWriter pw) {
596959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo        for (int i = 0; i < mLocalDevices.size(); ++i) {
597959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo            pw.println("HdmiCecLocalDevice #" + i + ":");
598959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo            pw.increaseIndent();
599959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo            mLocalDevices.valueAt(i).dump(pw);
600959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo            pw.decreaseIndent();
601959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo        }
602959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo    }
603959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo
6044085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
605a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native int nativeSendCecCommand(long controllerPtr, int srcAddress,
606e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            int dstAddress, byte[] body);
607a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
608a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native void nativeClearLogicalAddress(long controllerPtr);
609a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native int nativeGetPhysicalAddress(long controllerPtr);
610a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native int nativeGetVersion(long controllerPtr);
611a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    private static native int nativeGetVendorId(long controllerPtr);
6120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
613092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    private static native void nativeSetOption(long controllerPtr, int flag, int value);
614092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag);
615092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    private static native boolean nativeIsConnected(long controllerPtr, int port);
6160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
617