HdmiCecLocalDevice.java revision 25c20298ad04e0e591e0cfdc0bb9d01a985433ab
12918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/*
22918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Copyright (C) 2014 The Android Open Source Project
32918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim *
42918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License");
52918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * you may not use this file except in compliance with the License.
62918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * You may obtain a copy of the License at
72918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim *
82918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim *      http://www.apache.org/licenses/LICENSE-2.0
92918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim *
102918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Unless required by applicable law or agreed to in writing, software
112918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS,
122918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * See the License for the specific language governing permissions and
142918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * limitations under the License.
152918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */
162918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
172918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimpackage com.android.server.hdmi;
182918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
191a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jangimport android.hardware.hdmi.HdmiCecDeviceInfo;
204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport android.os.Handler;
2179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.os.Looper;
224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport android.os.Message;
23092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangimport android.util.Slog;
242918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
2579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport com.android.internal.annotations.GuardedBy;
26a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
2779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
2879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.ArrayList;
2943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kimimport java.util.Collections;
3079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.Iterator;
3179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.LinkedList;
3279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.List;
3379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
342918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/**
352918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Class that models a logical CEC device hosted in this system. Handles initialization,
362918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * CEC commands that call for actions customized per device type.
372918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */
382918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimabstract class HdmiCecLocalDevice {
39092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    private static final String TAG = "HdmiCecLocalDevice";
402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    // Timeout in millisecond for device clean up (5s).
434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    // Normal actions timeout is 2s but some of them would have several sequence of timeout.
444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    private static final int DEVICE_CLEANUP_TIMEOUT = 5000;
454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    protected final HdmiControlService mService;
472918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected final int mDeviceType;
482918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected int mAddress;
492918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected int mPreferredAddress;
501a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    protected HdmiCecDeviceInfo mDeviceInfo;
512918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
5272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    static class ActiveSource {
5372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        int logicalAddress;
5472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        int physicalAddress;
5572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim
5643c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim        public ActiveSource() {
5743c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim            invalidate();
5843c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim        }
5972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public ActiveSource(int logical, int physical) {
6072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            logicalAddress = logical;
6172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            physicalAddress = physical;
6272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
6372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public static ActiveSource of(int logical, int physical) {
6472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            return new ActiveSource(logical, physical);
6572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
6672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public boolean isValid() {
6772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            return HdmiUtils.isValidAddress(logicalAddress);
6872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
6943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim        public void invalidate() {
7043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim            logicalAddress = Constants.ADDR_INVALID;
7143c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim            physicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
7243c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim        }
7372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public boolean equals(int logical, int physical) {
7472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            return logicalAddress == logical && physicalAddress == physical;
7572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
7672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        @Override
7772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public boolean equals(Object obj) {
7872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            if (obj instanceof ActiveSource) {
7972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                ActiveSource that = (ActiveSource) obj;
8072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                return that.logicalAddress == logicalAddress &&
8172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                       that.physicalAddress == physicalAddress;
8272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            }
8372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            return false;
8472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
8572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        @Override
8672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        public int hashCode() {
8772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            return logicalAddress * 29 + physicalAddress;
8872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        }
8972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    }
9079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Logical address of the active source.
9179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @GuardedBy("mLock")
9243c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim    protected final ActiveSource mActiveSource = new ActiveSource();
9379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
9479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Active routing path. Physical address of the active source but not all the time, such as
9579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // when the new active source does not claim itself to be one. Note that we don't keep
9679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}.
9779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @GuardedBy("mLock")
9879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private int mActiveRoutingPath;
9979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
10079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
10179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final Object mLock;
10279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
10379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // A collection of FeatureAction.
10479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Note that access to this collection should happen in service thread.
10579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final LinkedList<FeatureAction> mActions = new LinkedList<>();
10679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
107c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    private final Handler mHandler = new Handler () {
1084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        @Override
1094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        public void handleMessage(Message msg) {
1104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang            switch (msg.what) {
1114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang                case MSG_DISABLE_DEVICE_TIMEOUT:
1124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang                    handleDisableDeviceTimeout();
1134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang                    break;
1144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang            }
1154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        }
1164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    };
1174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
1184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    /**
1194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * A callback interface to get notified when all pending action is cleared.
1204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * It can be called when timeout happened.
1214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     */
1224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    interface PendingActionClearedCallback {
1234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        void onCleared(HdmiCecLocalDevice device);
1244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    }
1254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
1264fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    protected PendingActionClearedCallback mPendingActionClearedCallback;
1274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
1283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) {
1293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mService = service;
1302918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mDeviceType = deviceType;
131c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        mAddress = Constants.ADDR_UNREGISTERED;
13279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mLock = service.getServiceLock();
1332918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
1342918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
1352918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Factory method that returns HdmiCecLocalDevice of corresponding type.
1363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) {
1372918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        switch (deviceType) {
138c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        case HdmiCecDeviceInfo.DEVICE_TV:
1393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            return new HdmiCecLocalDeviceTv(service);
140c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        case HdmiCecDeviceInfo.DEVICE_PLAYBACK:
1413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            return new HdmiCecLocalDevicePlayback(service);
1422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        default:
1432918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim            return null;
1442918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        }
1452918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
1462918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
147a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
1483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    void init() {
149a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
150af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim        mPreferredAddress = getPreferredAddress();
1513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    }
1522918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
1538b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang    /**
1543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang     * Called once a logical address of the local device is allocated.
1558b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang     */
156a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang    protected abstract void onAddressAllocated(int logicalAddress, boolean fromBootup);
1578b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang
158092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
159af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim     * Get the preferred logical address from system properties.
160af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim     */
161af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim    protected abstract int getPreferredAddress();
162af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim
163af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim    /**
164af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim     * Set the preferred logical address to system properties.
165af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim     */
166af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim    protected abstract void setPreferredAddress(int addr);
167af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim
168af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim    /**
169092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Dispatch incoming message.
170092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
171092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param message incoming message
172092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @return true if consumed a message; otherwise, return false.
173092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
174a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
17525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo    boolean dispatchMessage(HdmiCecMessage message) {
17679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
177092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int dest = message.getDestination();
178c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
179092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            return false;
180092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
18179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        // Cache incoming message. Note that it caches only white-listed one.
18279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mCecMessageCache.cacheMessage(message);
183092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return onMessage(message);
184092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
185092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
186a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
18760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    protected final boolean onMessage(HdmiCecMessage message) {
18879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
18979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        if (dispatchMessageToAction(message)) {
19079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return true;
19179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
192092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        switch (message.getOpcode()) {
193c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_ACTIVE_SOURCE:
1948333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim                return handleActiveSource(message);
195c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_INACTIVE_SOURCE:
1968333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim                return handleInactiveSource(message);
197c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
1988333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim                return handleRequestActiveSource(message);
199c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GET_MENU_LANGUAGE:
200092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGetMenuLanguage(message);
201c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
202092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGivePhysicalAddress();
203c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GIVE_OSD_NAME:
204092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGiveOsdName(message);
205c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
206092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGiveDeviceVendorId();
207c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GET_CEC_VERSION:
208092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGetCecVersion(message);
209c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
21060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang                return handleReportPhysicalAddress(message);
211c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_ROUTING_CHANGE:
21292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim                return handleRoutingChange(message);
213c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_INITIATE_ARC:
21479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleInitiateArc(message);
215c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_TERMINATE_ARC:
21679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleTerminateArc(message);
217c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE:
21879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleSetSystemAudioMode(message);
219c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
22079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleSystemAudioModeStatus(message);
221c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_REPORT_AUDIO_STATUS:
2228fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang                return handleReportAudioStatus(message);
223c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_STANDBY:
22438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleStandby(message);
225c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_TEXT_VIEW_ON:
22638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleTextViewOn(message);
227c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_IMAGE_VIEW_ON:
22838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleImageViewOn(message);
229c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_USER_CONTROL_PRESSED:
23038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleUserControlPressed(message);
231c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_SET_STREAM_PATH:
23238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleSetStreamPath(message);
233c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
23438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                return handleGiveDevicePowerStatus(message);
235119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            case Constants.MESSAGE_VENDOR_COMMAND:
236119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim                return handleVendorCommand(message);
237119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
238119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim                return handleVendorCommandWithId(message);
2398f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang            case Constants.MESSAGE_SET_OSD_NAME:
2408f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang                return handleSetOsdName(message);
241b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang            case Constants.MESSAGE_RECORD_TV_SCREEN:
242b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang                return handleRecordTvScreen(message);
243092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            default:
244092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return false;
245092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
246092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
247092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
248a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
24979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private boolean dispatchMessageToAction(HdmiCecMessage message) {
250a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
25179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
25279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.processCommand(message)) {
25379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return true;
25479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
25579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
25679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
25779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
259a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
260092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGivePhysicalAddress() {
26179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
26279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
263092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int physicalAddress = mService.getPhysicalAddress();
264092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
265092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, physicalAddress, mDeviceType);
266092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
267092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
268092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
269092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
270a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
271092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGiveDeviceVendorId() {
27279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
273092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int vendorId = mService.getVendorId();
274092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
275092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, vendorId);
276092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
277092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
278092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
279092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
280a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
281092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGetCecVersion(HdmiCecMessage message) {
28279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
283092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int version = mService.getCecVersion();
284092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
285092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                message.getSource(), version);
286092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
287092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
288092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
289092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
290a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
2918333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    protected boolean handleActiveSource(HdmiCecMessage message) {
2928333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        return false;
2938333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    }
2948333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim
2958333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    @ServiceThreadOnly
2968333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    protected boolean handleInactiveSource(HdmiCecMessage message) {
2978333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        return false;
2988333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    }
2998333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim
3008333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    @ServiceThreadOnly
3018333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
3028333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        return false;
3038333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    }
3048333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim
3058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    @ServiceThreadOnly
306092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
30779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
308092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
309092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(
310092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
311c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                        message.getSource(), Constants.MESSAGE_GET_MENU_LANGUAGE,
31225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo                        Constants.ABORT_UNRECOGNIZED_OPCODE));
313092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
314092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
315092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
316a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
317092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGiveOsdName(HdmiCecMessage message) {
31879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
319092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        // Note that since this method is called after logical address allocation is done,
320092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        // mDeviceInfo should not be null.
321092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
322092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, message.getSource(), mDeviceInfo.getDisplayName());
323092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        if (cecMessage != null) {
324092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            mService.sendCecCommand(cecMessage);
325092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        } else {
326092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName());
327092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
329092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
330092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
33192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    protected boolean handleRoutingChange(HdmiCecMessage message) {
33292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim        return false;
33392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim    }
33492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim
33560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
33660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang        return false;
33760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    }
33860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang
33979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
34079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
34179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
34279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
34379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
34479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
34579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
34679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
34779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleTerminateArc(HdmiCecMessage message) {
34879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
34979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
35079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
35179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleInitiateArc(HdmiCecMessage message) {
35279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
3538fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang    }
3548fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang
3558fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang    protected boolean handleReportAudioStatus(HdmiCecMessage message) {
3568fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang        return false;
35779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
35879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
359a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
36038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleStandby(HdmiCecMessage message) {
36138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        assertRunOnServiceThread();
36238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        // Seq #12
3634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim        if (mService.isControlEnabled() && !mService.isProhibitMode()
36438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                && mService.isPowerOnOrTransient()) {
36538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            mService.standby();
36638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            return true;
36738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        }
36838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return false;
36938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
37038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
37138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    @ServiceThreadOnly
37238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleUserControlPressed(HdmiCecMessage message) {
37338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        assertRunOnServiceThread();
37438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) {
37538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            mService.standby();
37638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            return true;
37738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) {
37838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            mService.wakeUp();
37938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            return true;
38038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        }
38138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return false;
38238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
38338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
38425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo    static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
38538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        byte[] params = message.getParams();
386c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
387210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
388210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION
389210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
39038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
39138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
39225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo    static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
39338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        byte[] params = message.getParams();
394c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
395210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
396210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION
397210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
39838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
39938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
40038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleTextViewOn(HdmiCecMessage message) {
40138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return false;
40238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
40338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
40438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleImageViewOn(HdmiCecMessage message) {
40538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return false;
40638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
40738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
40838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleSetStreamPath(HdmiCecMessage message) {
40938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return false;
41038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
41138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
41238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) {
41338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus(
41438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo                mAddress, message.getSource(), mService.getPowerStatus()));
41538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        return true;
41638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
41738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
418119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    protected boolean handleVendorCommand(HdmiCecMessage message) {
419119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
420119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim                message.getParams(), false);
421119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        return true;
422119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    }
423119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim
424119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    protected boolean handleVendorCommandWithId(HdmiCecMessage message) {
425119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        byte[] params = message.getParams();
426119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        int vendorId = HdmiUtils.threeBytesToInt(params);
427119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        if (vendorId == mService.getVendorId()) {
428119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params, true);
429119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        } else if (message.getDestination() != Constants.ADDR_BROADCAST &&
430119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim                message.getSource() != Constants.ADDR_UNREGISTERED) {
431119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
432119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
433119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim                    message.getSource(), Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
43425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo                    Constants.ABORT_UNRECOGNIZED_OPCODE));
435119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        } else {
436119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim            Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
437119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        }
438119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim        return true;
439119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim    }
440119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim
4418f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang    protected boolean handleSetOsdName(HdmiCecMessage message) {
4428f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang        // The default behavior of <Set Osd Name> is doing nothing.
4438f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang        return true;
4448f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang    }
4458f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang
446b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
44725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo        // The default behavior of <Record TV Screen> is replying <Feature Abort> with
44825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo        // "Cannot provide source".
449b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
45025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo                message.getSource(), message.getOpcode(), Constants.ABORT_CANNOT_PROVIDE_SOURCE));
451b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang        return true;
452b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang    }
453b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang
45438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    @ServiceThreadOnly
455a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang    final void handleAddressAllocated(int logicalAddress, boolean fromBootup) {
45679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
4573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mAddress = mPreferredAddress = logicalAddress;
458a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang        onAddressAllocated(logicalAddress, fromBootup);
459af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim        setPreferredAddress(logicalAddress);
4601a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
4611a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
462a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
4631a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    HdmiCecDeviceInfo getDeviceInfo() {
46479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
4651a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang        return mDeviceInfo;
4661a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
4671a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
468a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
4691a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    void setDeviceInfo(HdmiCecDeviceInfo info) {
47079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
4711a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang        mDeviceInfo = info;
4721a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
4731a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
4742918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Returns true if the logical address is same as the argument.
475a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
4762918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    boolean isAddressOf(int addr) {
47779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
4782918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        return addr == mAddress;
4792918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
4802918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
4812918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Resets the logical address to unregistered(15), meaning the logical device is invalid.
482a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
4832918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    void clearAddress() {
48479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
485c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        mAddress = Constants.ADDR_UNREGISTERED;
4862918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
4872918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
488a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
48979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void addAndStartAction(final FeatureAction action) {
49079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
49138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        if (mService.isPowerStandbyOrTransient()) {
49238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            Slog.w(TAG, "Skip the action during Standby: " + action);
49338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo            return;
49438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        }
49579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActions.add(action);
49679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        action.start();
49779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
49879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
49979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // See if we have an action of a given type in progress.
500a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
50179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
50279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
50379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
50479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.getClass().equals(clazz)) {
50579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return true;
50679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
50779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
50879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
50979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
51079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
51179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Returns all actions matched with given class type.
512a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
51379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
51479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
51543c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim        List<T> actions = Collections.<T>emptyList();
51679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
51779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.getClass().equals(clazz)) {
51843c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim                if (actions.isEmpty()) {
51943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim                    actions = new ArrayList<T>();
52043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim                }
52179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                actions.add((T) action);
52279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
52379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
52479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return actions;
52579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
52679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
52779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
52879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Remove the given {@link FeatureAction} object from the action queue.
52979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
53079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param action {@link FeatureAction} to remove
53179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
532a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
53379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void removeAction(final FeatureAction action) {
53479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
535c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        action.finish(false);
53679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActions.remove(action);
53738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        checkIfPendingActionsCleared();
53879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
53979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
54079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Remove all actions matched with the given Class type.
541a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
54279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> void removeAction(final Class<T> clazz) {
543a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
54479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        removeActionExcept(clazz, null);
54579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
54679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
54779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Remove all actions matched with the given Class type besides |exception|.
548a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
54979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
55079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            final FeatureAction exception) {
55179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
55279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        Iterator<FeatureAction> iter = mActions.iterator();
55379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        while (iter.hasNext()) {
55479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            FeatureAction action = iter.next();
55579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action != exception && action.getClass().equals(clazz)) {
556c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                action.finish(false);
557c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                iter.remove();
55879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
55979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
56038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        checkIfPendingActionsCleared();
56179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
56279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
56338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    protected void checkIfPendingActionsCleared() {
5644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        if (mActions.isEmpty() && mPendingActionClearedCallback != null) {
56526ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo            PendingActionClearedCallback callback = mPendingActionClearedCallback;
56626ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo            // To prevent from calling the callback again during handling the callback itself.
56726ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo            mPendingActionClearedCallback = null;
56826ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo            callback.onCleared(this);
56938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo        }
57038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    }
5714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
57279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected void assertRunOnServiceThread() {
57379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        if (Looper.myLooper() != mService.getServiceLooper()) {
57479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            throw new IllegalStateException("Should run on service thread.");
57579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
57679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
57779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
57879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
57979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Called when a hot-plug event issued.
58079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
58179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param portId id of port where a hot-plug event happened
58279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param connected whether to connected or not on the event
58379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
58479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void onHotplug(int portId, boolean connected) {
58579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
58679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
58779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    final HdmiControlService getService() {
58879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService;
58979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
59079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
591a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
59279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    final boolean isConnectedToArcPort(int path) {
593a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang        assertRunOnServiceThread();
59479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService.isConnectedToArcPort(path);
59579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
59679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
59772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    ActiveSource getActiveSource() {
59879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
59979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mActiveSource;
60079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
60179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
60279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
60372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    void setActiveSource(ActiveSource newActive) {
60472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
60572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    }
60672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim
60772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    void setActiveSource(HdmiCecDeviceInfo info) {
60872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim        setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
60972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    }
61072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim
61172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim    void setActiveSource(int logicalAddress, int physicalAddress) {
6128333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        synchronized (mLock) {
61372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            mActiveSource.logicalAddress = logicalAddress;
61472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            mActiveSource.physicalAddress = physicalAddress;
6158333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        }
6168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    }
6178333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim
61879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int getActivePath() {
61979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
62079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mActiveRoutingPath;
62179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
62279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
62379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
6248333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    void setActivePath(int path) {
6258333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        synchronized (mLock) {
6268333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim            mActiveRoutingPath = path;
6278333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        }
6288333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    }
6298333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim
63079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
631a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     * Returns the ID of the active HDMI port. The active port is the one that has the active
632a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     * routing path connected to it directly or indirectly under the device hierarchy.
63379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
634a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim    int getActivePortId() {
63579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
63679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mService.pathToPortId(mActiveRoutingPath);
63779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
63879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
63979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
640a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim    /**
641a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     * Update the active port.
642a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     *
643a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     * @param portId the new active port id
644a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim     */
645a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim    void setActivePortId(int portId) {
646a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim        synchronized (mLock) {
647a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim            // We update active routing path instead, since we get the active port id from
648a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim            // the active routing path.
649a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim            mActiveRoutingPath = mService.portIdToPath(portId);
650a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim        }
651a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim    }
652a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim
653a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
65479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    HdmiCecMessageCache getCecMessageCache() {
65579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
65679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mCecMessageCache;
65779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
65879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
659a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang    @ServiceThreadOnly
66079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int pathToPortId(int newPath) {
66179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
66279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService.pathToPortId(newPath);
66379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
66438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
66538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    /**
6664fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * Called when the system goes to standby mode.
66738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo     *
66838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo     * @param initiatedByCec true if this power sequence is initiated
669b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang     *        by the reception the CEC messages like &lt;Standby&gt;
67038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo     */
6714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    protected void onStandby(boolean initiatedByCec) {}
67238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo
67338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo    /**
6744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * Disable device. {@code callback} is used to get notified when all pending
6754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * actions are completed or timeout is issued.
67638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo     *
6774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * @param initiatedByCec true if this sequence is initiated
678b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang     *        by the reception the CEC messages like &lt;Standby&gt;
679b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang     * @param origialCallback callback interface to get notified when all pending actions are
680b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang     *        cleared
68138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo     */
682b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang    protected void disableDevice(boolean initiatedByCec,
683b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang            final PendingActionClearedCallback origialCallback) {
684b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang        mPendingActionClearedCallback = new PendingActionClearedCallback() {
685b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang            @Override
686b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang            public void onCleared(HdmiCecLocalDevice device) {
687b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang                mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT);
688b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang                origialCallback.onCleared(device);
689b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang            }
690b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang        };
6914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_DISABLE_DEVICE_TIMEOUT),
6924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang                DEVICE_CLEANUP_TIMEOUT);
6934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    }
6944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
6954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    @ServiceThreadOnly
6964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    private void handleDisableDeviceTimeout() {
6974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        assertRunOnServiceThread();
6984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang
6994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        // If all actions are not cleared in DEVICE_CLEANUP_TIMEOUT, enforce to finish them.
7004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        // onCleard will be called at the last action's finish method.
7014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        Iterator<FeatureAction> iter = mActions.iterator();
7024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        while (iter.hasNext()) {
7034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang            FeatureAction action = iter.next();
704c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            action.finish(false);
7054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang            iter.remove();
7064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang        }
7074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang    }
708c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim
709c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim    /**
710c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim     * Send a key event to other device.
711c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim     *
7124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang     * @param keyCode key code defined in {@link android.view.KeyEvent}
713c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim     * @param isPressed {@code true} for key down event
714c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim     */
715c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim    protected void sendKeyEvent(int keyCode, boolean isPressed) {
716c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim        Slog.w(TAG, "sendKeyEvent not implemented");
717c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim    }
7182918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim}
719