HdmiCecController.java revision 7d9a843af83dbc75b1d170c743603198ede5a10f
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
19e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.hardware.hdmi.HdmiCec;
207d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport android.hardware.hdmi.HdmiCecDeviceInfo;
21e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.hardware.hdmi.HdmiCecMessage;
220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.Handler;
230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.Looper;
240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.Message;
25e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.util.Slog;
267d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport android.util.SparseArray;
27e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
287d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.ArrayList;
29e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport java.util.Arrays;
307d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jangimport java.util.List;
310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/**
330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * and pass it to CEC HAL so that it sends message to other device. For incoming
350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * message it translates the message and delegates it to proper module.
360792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>It can be created only by {@link HdmiCecController#create}
380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */
410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangclass HdmiCecController {
420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private static final String TAG = "HdmiCecController";
430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
44e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // A message to pass cec send command to IO looper.
45e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int MSG_SEND_CEC_COMMAND = 1;
46e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
47e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // Message types to handle incoming message in main service looper.
48e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private final static int MSG_RECEIVE_CEC_COMMAND = 1;
49e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
50e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // TODO: move these values to HdmiCec.java once make it internal constant class.
51e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // CEC's ABORT reason values.
52e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_UNRECOGNIZED_MODE = 0;
53e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_NOT_IN_CORRECT_MODE = 1;
54e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
55e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_INVALID_OPERAND = 3;
56e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_REFUSED = 4;
57e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static final int ABORT_UNABLE_TO_DETERMINE = 5;
58e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Handler instance to process synchronous I/O (mainly send) message.
600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private Handler mIoHandler;
610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Handler instance to process various messages coming from other CEC
630792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // device or issued by internal state change.
64e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private Handler mControlHandler;
650792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Stores the pointer to the native implementation of the service that
670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // interacts with HAL.
680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private long mNativePtr;
690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
707d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    // Map-like container of all cec devices. A logical address of device is
717d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    // used as key of container.
727d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
737d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang            new SparseArray<HdmiCecDeviceInfo>();
747d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    // Private constructor.  Use HdmiCecController.create().
760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private HdmiCecController() {
770792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
790792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /**
800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * A factory method to get {@link HdmiCecController}. If it fails to initialize
810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * inner device or has no device it will return {@code null}.
820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     *
830792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
84e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * @param service {@link HdmiControlService} instance used to create internal handler
85e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     *                and to pass callback for incoming message or event.
860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     *         returns {@code null}.
880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     */
89e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    static HdmiCecController create(HdmiControlService service) {
900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        HdmiCecController handler = new HdmiCecController();
910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        long nativePtr = nativeInit(handler);
920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        if (nativePtr == 0L) {
930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang            handler = null;
940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang            return null;
950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        }
960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
97e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        handler.init(service, nativePtr);
980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        return handler;
990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
1000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
101e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static byte[] buildBody(int opcode, byte[] params) {
102e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        byte[] body = new byte[params.length + 1];
103e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        body[0] = (byte) opcode;
104e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        System.arraycopy(params, 0, body, 1, params.length);
105e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        return body;
106e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
107e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
108e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private final class IoHandler extends Handler {
109e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        private IoHandler(Looper looper) {
110e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            super(looper);
111e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        }
112e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
113e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        @Override
114e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        public void handleMessage(Message msg) {
115e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            switch (msg.what) {
116e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                case MSG_SEND_CEC_COMMAND:
117e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    HdmiCecMessage cecMessage = (HdmiCecMessage) msg.obj;
118e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
119e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
120e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                            cecMessage.getDestination(), body);
121e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    break;
122e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                default:
123e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
124e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    break;
125e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            }
126e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        }
127e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
128e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
129e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private final class ControlHandler extends Handler {
130e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        private ControlHandler(Looper looper) {
131e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            super(looper);
132e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        }
133e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
134e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        @Override
135e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        public void handleMessage(Message msg) {
136e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            switch (msg.what) {
137e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                case MSG_RECEIVE_CEC_COMMAND:
138e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    // TODO: delegate it to HdmiControl service.
139e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    onReceiveCommand((HdmiCecMessage) msg.obj);
140e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    break;
141e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                default:
142e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    Slog.i(TAG, "Unsupported message type:" + msg.what);
143e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                    break;
1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang            }
145e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        }
146e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
1470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1487d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    /**
1497d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
1507d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * logical address as new device info's.
1517d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
1527d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
1537d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
1547d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
1557d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
1567d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *         that has the same logical address as new one has.
1577d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     */
1587d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
1597d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
1607d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        if (oldDeviceInfo != null) {
1617d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang            removeDeviceInfo(deviceInfo.getLogicalAddress());
1627d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        }
1637d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
1647d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        return oldDeviceInfo;
1657d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    }
1667d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
1677d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    /**
1687d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * Remove a device info corresponding to the given {@code logicalAddress}.
1697d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * It returns removed {@link HdmiCecDeviceInfo} if exists.
1707d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
1717d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
1727d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
1737d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @param logicalAddress logical address of device to be removed
1747d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
1757d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     */
1767d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
1777d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
1787d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        if (deviceInfo != null) {
1797d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang            mDeviceInfos.remove(logicalAddress);
1807d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        }
1817d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        return deviceInfo;
1827d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    }
1837d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
1847d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    /**
1857d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * Return a list of all {@HdmiCecDeviceInfo}.
1867d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
1877d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
1887d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     */
1897d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    List<HdmiCecDeviceInfo> getDeviceInfoList() {
1907d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        List<HdmiCecDeviceInfo> deviceInfoList = new ArrayList<HdmiCecDeviceInfo>(
1917d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang                mDeviceInfos.size());
1927d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        for (int i = 0; i < mDeviceInfos.size(); ++i) {
1937d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang            deviceInfoList.add(mDeviceInfos.valueAt(i));
1947d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        }
1957d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        return deviceInfoList;
1967d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    }
1977d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
1987d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    /**
1997d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
2007d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
2017d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
2027d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *
2037d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @param logicalAddress logical address to be retrieved
2047d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
2057d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     *         Returns null if no logical address matched
2067d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang     */
2077d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
2087d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang        return mDeviceInfos.get(logicalAddress);
2097d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang    }
2107d9a843af83dbc75b1d170c743603198ede5a10fJungshik Jang
211e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void init(HdmiControlService service, long nativePtr) {
212e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        mIoHandler = new IoHandler(service.getServiceLooper());
213e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        mControlHandler = new ControlHandler(service.getServiceLooper());
2140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        mNativePtr = nativePtr;
2150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
2160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
217e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void onReceiveCommand(HdmiCecMessage message) {
218e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        // TODO: Handle message according to opcode type.
219e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
220e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        // TODO: Use device's source address for broadcast message.
221e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ?
222e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                message.getDestination() : 0;
223e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        // Reply <Feature Abort> to initiator (source) for all requests.
224e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(),
225e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                ABORT_REFUSED);
226e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
227e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
228e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode,
229e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            int reason) {
230e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        byte[] params = new byte[2];
231e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        params[0] = (byte) originalOpcode;
232e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        params[1] = (byte) reason;
233e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
234e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress,
235e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                HdmiCec.MESSAGE_FEATURE_ABORT, params);
236e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
237e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        mIoHandler.sendMessage(message);
238e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
239e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
240e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    /**
241e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * Called by native when incoming CEC message arrived.
242e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     */
243e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
244e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        byte opcode = body[0];
245e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        byte params[] = Arrays.copyOfRange(body, 1, body.length);
246e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
247e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
248e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        // Delegate message to main handler so that it handles in main thread.
249e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        Message message = mControlHandler.obtainMessage(
250e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang                MSG_RECEIVE_CEC_COMMAND, cecMessage);
251e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        mControlHandler.sendMessage(message);
252e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
253e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
2540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /**
255e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang     * Called by native when a hotplug event issues.
2560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang     */
257e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private void handleHotplug(boolean connected) {
258e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        // TODO: Delegate event to main message handler.
2590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
2600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
2610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    private static native long nativeInit(HdmiCecController handler);
262e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    private static native int nativeSendCecCommand(long contollerPtr, int srcAddress,
263e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            int dstAddress, byte[] body);
2640792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
265