HdmiCecLocalDevice.java revision 79c58a4b97f27ede6a1b680d2fece9c2a0edf7b7
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
192918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimimport android.hardware.hdmi.HdmiCec;
201a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jangimport android.hardware.hdmi.HdmiCecDeviceInfo;
21092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangimport android.hardware.hdmi.HdmiCecMessage;
2279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.os.Looper;
23092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangimport android.util.Slog;
242918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
2579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport com.android.internal.annotations.GuardedBy;
2679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
2779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.ArrayList;
2879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.Iterator;
2979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.LinkedList;
3079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.List;
3179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
322918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/**
332918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Class that models a logical CEC device hosted in this system. Handles initialization,
342918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * CEC commands that call for actions customized per device type.
352918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */
362918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimabstract class HdmiCecLocalDevice {
37092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    private static final String TAG = "HdmiCecLocalDevice";
382918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    protected final HdmiControlService mService;
402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected final int mDeviceType;
412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected int mAddress;
422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    protected int mPreferredAddress;
431a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    protected HdmiCecDeviceInfo mDeviceInfo;
442918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
4579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Logical address of the active source.
4679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @GuardedBy("mLock")
4779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private int mActiveSource;
4879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
4979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Active routing path. Physical address of the active source but not all the time, such as
5079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // when the new active source does not claim itself to be one. Note that we don't keep
5179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}.
5279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @GuardedBy("mLock")
5379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private int mActiveRoutingPath;
5479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
5579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Set to true while the service is in normal mode. While set to false, no input change is
5679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // allowed. Used for situations where input change can confuse users such as channel auto-scan,
5779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // system upgrade, etc., a.k.a. "prohibit mode".
5879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @GuardedBy("mLock")
5979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private boolean mInputChangeEnabled;
6079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
6179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
6279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final Object mLock;
6379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
6479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // A collection of FeatureAction.
6579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Note that access to this collection should happen in service thread.
6679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final LinkedList<FeatureAction> mActions = new LinkedList<>();
6779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) {
693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mService = service;
702918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mDeviceType = deviceType;
712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mAddress = HdmiCec.ADDR_UNREGISTERED;
7279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mLock = service.getServiceLock();
7379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
7479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        // TODO: Get control flag from persistent storage
7579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mInputChangeEnabled = true;
762918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
772918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
782918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Factory method that returns HdmiCecLocalDevice of corresponding type.
793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) {
802918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        switch (deviceType) {
812918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        case HdmiCec.DEVICE_TV:
823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            return new HdmiCecLocalDeviceTv(service);
832918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        case HdmiCec.DEVICE_PLAYBACK:
843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang            return new HdmiCecLocalDevicePlayback(service);
852918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        default:
862918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim            return null;
872918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        }
882918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
892918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    void init() {
913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mPreferredAddress = HdmiCec.ADDR_UNREGISTERED;
923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        // TODO: load preferred address from permanent storage.
933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    }
942918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
958b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang    /**
963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang     * Called once a logical address of the local device is allocated.
978b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang     */
988b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang    protected abstract void onAddressAllocated(int logicalAddress);
998b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang
100092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    /**
101092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * Dispatch incoming message.
102092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     *
103092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @param message incoming message
104092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     * @return true if consumed a message; otherwise, return false.
105092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang     */
106092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    final boolean dispatchMessage(HdmiCecMessage message) {
10779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
10879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
109092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int dest = message.getDestination();
110092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) {
111092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            return false;
112092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
11379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        // Cache incoming message. Note that it caches only white-listed one.
11479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mCecMessageCache.cacheMessage(message);
115092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return onMessage(message);
116092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
117092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
11860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    protected final boolean onMessage(HdmiCecMessage message) {
11979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
12079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
12179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        if (dispatchMessageToAction(message)) {
12279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return true;
12379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
124092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        switch (message.getOpcode()) {
125092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
126092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGetMenuLanguage(message);
127092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
128092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGivePhysicalAddress();
129092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            case HdmiCec.MESSAGE_GIVE_OSD_NAME:
130092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGiveOsdName(message);
131092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
132092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGiveDeviceVendorId();
133092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            case HdmiCec.MESSAGE_GET_CEC_VERSION:
134092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return handleGetCecVersion(message);
13560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang            case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
13660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang                return handleReportPhysicalAddress(message);
13779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            case HdmiCec.MESSAGE_INITIATE_ARC:
13879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleInitiateArc(message);
13979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            case HdmiCec.MESSAGE_TERMINATE_ARC:
14079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleTerminateArc(message);
14179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
14279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleSetSystemAudioMode(message);
14379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
14479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return handleSystemAudioModeStatus(message);
145092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            default:
146092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                return false;
147092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
148092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
149092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
15079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private boolean dispatchMessageToAction(HdmiCecMessage message) {
15179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
15279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.processCommand(message)) {
15379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return true;
15479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
15579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
15679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
15779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
15879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
159092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGivePhysicalAddress() {
16079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
16179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
162092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int physicalAddress = mService.getPhysicalAddress();
163092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
164092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, physicalAddress, mDeviceType);
165092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
166092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
167092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
168092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
169092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGiveDeviceVendorId() {
17079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
17179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
172092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int vendorId = mService.getVendorId();
173092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
174092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, vendorId);
175092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
176092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
177092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
178092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
179092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGetCecVersion(HdmiCecMessage message) {
18079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
18179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
182092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        int version = mService.getCecVersion();
183092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
184092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                message.getSource(), version);
185092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(cecMessage);
186092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
187092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
188092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
189092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
19079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
19179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
192092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
193092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        mService.sendCecCommand(
194092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
195092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                        message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
196092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                        HdmiConstants.ABORT_UNRECOGNIZED_MODE));
197092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
198092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
199092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
200092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    protected boolean handleGiveOsdName(HdmiCecMessage message) {
20179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
203092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        // Note that since this method is called after logical address allocation is done,
204092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        // mDeviceInfo should not be null.
205092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
206092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang                mAddress, message.getSource(), mDeviceInfo.getDisplayName());
207092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        if (cecMessage != null) {
208092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            mService.sendCecCommand(cecMessage);
209092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        } else {
210092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang            Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName());
211092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        }
212092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang        return true;
213092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    }
214092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
2150a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim    protected boolean handleVendorSpecificCommand(HdmiCecMessage message) {
2160a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim        return false;
2170a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim    }
2180a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim
21960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
22060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang        return false;
22160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang    }
22260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang
22379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
22479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
22579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
22679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
22779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
22879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
22979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
23079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
23179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleTerminateArc(HdmiCecMessage message) {
23279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
23379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
23479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
23579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected boolean handleInitiateArc(HdmiCecMessage message) {
23679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
23779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
23879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
2393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    final void handleAddressAllocated(int logicalAddress) {
24079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
24179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
2423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        mAddress = mPreferredAddress = logicalAddress;
2433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        onAddressAllocated(logicalAddress);
2441a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
2451a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
2461a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    HdmiCecDeviceInfo getDeviceInfo() {
24779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2481a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang        return mDeviceInfo;
2491a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
2501a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
2511a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    void setDeviceInfo(HdmiCecDeviceInfo info) {
25279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2531a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang        mDeviceInfo = info;
2541a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang    }
2551a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang
2562918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Returns true if the logical address is same as the argument.
2572918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    boolean isAddressOf(int addr) {
25879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2592918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        return addr == mAddress;
2602918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
2612918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
2622918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    // Resets the logical address to unregistered(15), meaning the logical device is invalid.
2632918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    void clearAddress() {
26479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2652918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mAddress = HdmiCec.ADDR_UNREGISTERED;
2662918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
2672918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim
2682918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    void setPreferredAddress(int addr) {
26979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2702918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim        mPreferredAddress = addr;
2712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim    }
2723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang
2733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    int getPreferredAddress() {
27479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
2753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang        return mPreferredAddress;
2763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang    }
27779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
27879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void addAndStartAction(final FeatureAction action) {
27979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
28079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActions.add(action);
28179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        action.start();
28279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
28379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
28479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // See if we have an action of a given type in progress.
28579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
28679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
28779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
28879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.getClass().equals(clazz)) {
28979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return true;
29079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
29179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
29279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return false;
29379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
29479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
29579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Returns all actions matched with given class type.
29679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
29779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
29879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        ArrayList<T> actions = new ArrayList<>();
29979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        for (FeatureAction action : mActions) {
30079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action.getClass().equals(clazz)) {
30179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                actions.add((T) action);
30279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
30379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
30479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return actions;
30579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
30679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
30779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
30879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Remove the given {@link FeatureAction} object from the action queue.
30979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
31079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param action {@link FeatureAction} to remove
31179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
31279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void removeAction(final FeatureAction action) {
31379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
31479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActions.remove(action);
31579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
31679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
31779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Remove all actions matched with the given Class type.
31879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> void removeAction(final Class<T> clazz) {
31979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        removeActionExcept(clazz, null);
32079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
32179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
32279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // Remove all actions matched with the given Class type besides |exception|.
32379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
32479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            final FeatureAction exception) {
32579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
32679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        Iterator<FeatureAction> iter = mActions.iterator();
32779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        while (iter.hasNext()) {
32879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            FeatureAction action = iter.next();
32979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (action != exception && action.getClass().equals(clazz)) {
33079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                action.clear();
33179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                mActions.remove(action);
33279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
33379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
33479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
33579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
33679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected void assertRunOnServiceThread() {
33779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        if (Looper.myLooper() != mService.getServiceLooper()) {
33879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            throw new IllegalStateException("Should run on service thread.");
33979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
34079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
34179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
34279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
34379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Called when a hot-plug event issued.
34479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
34579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param portId id of port where a hot-plug event happened
34679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param connected whether to connected or not on the event
34779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
34879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void onHotplug(int portId, boolean connected) {
34979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
35079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
35179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    final HdmiControlService getService() {
35279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService;
35379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
35479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
35579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    final boolean isConnectedToArcPort(int path) {
35679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService.isConnectedToArcPort(path);
35779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
35879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
35979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int getActiveSource() {
36079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
36179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mActiveSource;
36279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
36379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
36479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
36579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
36679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Returns the active routing path.
36779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
36879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int getActivePath() {
36979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
37079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mActiveRoutingPath;
37179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
37279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
37379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
37479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
37579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Returns the ID of the active HDMI port. The active input is the port that has the active
37679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * routing path connected directly or indirectly under the device hierarchy.
37779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
37879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int getActiveInput() {
37979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
38079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return mService.pathToPortId(mActiveRoutingPath);
38179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
38279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
38379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
38479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void updateActiveDevice(int logicalAddress, int physicalAddress) {
38579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
38679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            mActiveSource = logicalAddress;
38779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            mActiveRoutingPath = physicalAddress;
38879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
38979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
39079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
39179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    void setInputChangeEnabled(boolean enabled) {
39279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
39379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            mInputChangeEnabled = enabled;
39479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
39579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
39679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
39779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    boolean isInPresetInstallationMode() {
39879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
39979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return !mInputChangeEnabled;
40079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
40179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
40279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
40379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
40479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Whether the given path is located in the tail of current active path.
40579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
40679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param path to be tested
40779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @return true if the given path is located in the tail of current active path; otherwise,
40879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *         false
40979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
41079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    // TODO: move this to local device tv.
41179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    boolean isTailOfActivePath(int path) {
41279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        synchronized (mLock) {
41379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            // If active routing path is internal source, return false.
41479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            if (mActiveRoutingPath == 0) {
41579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                return false;
41679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
41779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            for (int i = 12; i >= 0; i -= 4) {
41879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                int curActivePath = (mActiveRoutingPath >> i) & 0xF;
41979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                if (curActivePath == 0) {
42079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                    return true;
42179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                } else {
42279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                    int curPath = (path >> i) & 0xF;
42379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                    if (curPath != curActivePath) {
42479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                        return false;
42579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                    }
42679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                }
42779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            }
42879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            return false;
42979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        }
43079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
43179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
43279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    HdmiCecMessageCache getCecMessageCache() {
43379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
43479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mCecMessageCache;
43579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
43679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
43779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    int pathToPortId(int newPath) {
43879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        assertRunOnServiceThread();
43979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mService.pathToPortId(newPath);
44079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
4412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim}
442