17fa3a66470d2133796defd14a0600578758882acJinsuk Kim/* 27fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Copyright (C) 2014 The Android Open Source Project 37fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 47fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License"); 57fa3a66470d2133796defd14a0600578758882acJinsuk Kim * you may not use this file except in compliance with the License. 67fa3a66470d2133796defd14a0600578758882acJinsuk Kim * You may obtain a copy of the License at 77fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 87fa3a66470d2133796defd14a0600578758882acJinsuk Kim * http://www.apache.org/licenses/LICENSE-2.0 97fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 107fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Unless required by applicable law or agreed to in writing, software 117fa3a66470d2133796defd14a0600578758882acJinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS, 127fa3a66470d2133796defd14a0600578758882acJinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137fa3a66470d2133796defd14a0600578758882acJinsuk Kim * See the License for the specific language governing permissions and 147fa3a66470d2133796defd14a0600578758882acJinsuk Kim * limitations under the License. 157fa3a66470d2133796defd14a0600578758882acJinsuk Kim */ 167fa3a66470d2133796defd14a0600578758882acJinsuk Kim 177fa3a66470d2133796defd14a0600578758882acJinsuk Kimpackage com.android.server.hdmi; 187fa3a66470d2133796defd14a0600578758882acJinsuk Kim 197fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.hardware.hdmi.HdmiDeviceInfo; 207fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport java.util.ArrayList; 217fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport java.util.Iterator; 227fa3a66470d2133796defd14a0600578758882acJinsuk Kim 237fa3a66470d2133796defd14a0600578758882acJinsuk Kim/** 247fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Buffer storage to keep incoming messages for later processing. Used to 257fa3a66470d2133796defd14a0600578758882acJinsuk Kim * handle messages that arrive when the device is not ready. Useful when 267fa3a66470d2133796defd14a0600578758882acJinsuk Kim * keeping the messages from a connected device which are not discovered yet. 277fa3a66470d2133796defd14a0600578758882acJinsuk Kim */ 287fa3a66470d2133796defd14a0600578758882acJinsuk Kimfinal class DelayedMessageBuffer { 297fa3a66470d2133796defd14a0600578758882acJinsuk Kim private final ArrayList<HdmiCecMessage> mBuffer = new ArrayList<>(); 307fa3a66470d2133796defd14a0600578758882acJinsuk Kim private final HdmiCecLocalDevice mDevice; 317fa3a66470d2133796defd14a0600578758882acJinsuk Kim 327fa3a66470d2133796defd14a0600578758882acJinsuk Kim DelayedMessageBuffer(HdmiCecLocalDevice device) { 337fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDevice = device; 347fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 357fa3a66470d2133796defd14a0600578758882acJinsuk Kim 367fa3a66470d2133796defd14a0600578758882acJinsuk Kim /** 377fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Add a new message to the buffer. The buffer keeps selected messages in 387fa3a66470d2133796defd14a0600578758882acJinsuk Kim * the order they are received. 397fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 407fa3a66470d2133796defd14a0600578758882acJinsuk Kim * @param message {@link HdmiCecMessage} to add 417fa3a66470d2133796defd14a0600578758882acJinsuk Kim */ 427fa3a66470d2133796defd14a0600578758882acJinsuk Kim void add(HdmiCecMessage message) { 437fa3a66470d2133796defd14a0600578758882acJinsuk Kim boolean buffered = true; 447fa3a66470d2133796defd14a0600578758882acJinsuk Kim 457fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Note that all the messages are not handled in the same manner. 467fa3a66470d2133796defd14a0600578758882acJinsuk Kim // For <Active Source> we keep the latest one only. 477fa3a66470d2133796defd14a0600578758882acJinsuk Kim // TODO: This might not be the best way to choose the active source. 487fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Devise a better way to pick up the best one. 497fa3a66470d2133796defd14a0600578758882acJinsuk Kim switch (message.getOpcode()) { 507fa3a66470d2133796defd14a0600578758882acJinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 517fa3a66470d2133796defd14a0600578758882acJinsuk Kim removeActiveSource(); 527fa3a66470d2133796defd14a0600578758882acJinsuk Kim mBuffer.add(message); 537fa3a66470d2133796defd14a0600578758882acJinsuk Kim break; 547fa3a66470d2133796defd14a0600578758882acJinsuk Kim case Constants.MESSAGE_INITIATE_ARC: 55ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE: 567fa3a66470d2133796defd14a0600578758882acJinsuk Kim mBuffer.add(message); 577fa3a66470d2133796defd14a0600578758882acJinsuk Kim break; 587fa3a66470d2133796defd14a0600578758882acJinsuk Kim default: 597fa3a66470d2133796defd14a0600578758882acJinsuk Kim buffered = false; 607fa3a66470d2133796defd14a0600578758882acJinsuk Kim break; 617fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 627fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (buffered) { 637fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiLogger.debug("Buffering message:" + message); 647fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 657fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 667fa3a66470d2133796defd14a0600578758882acJinsuk Kim 677fa3a66470d2133796defd14a0600578758882acJinsuk Kim private void removeActiveSource() { 687fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Uses iterator to remove elements while looping through the list. 697fa3a66470d2133796defd14a0600578758882acJinsuk Kim for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) { 707fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiCecMessage message = iter.next(); 717fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE) { 727fa3a66470d2133796defd14a0600578758882acJinsuk Kim iter.remove(); 737fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 747fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 757fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 767fa3a66470d2133796defd14a0600578758882acJinsuk Kim 772ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim boolean isBuffered(int opcode) { 782ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim for (HdmiCecMessage message : mBuffer) { 792ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim if (message.getOpcode() == opcode) { 802ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim return true; 812ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim } 822ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim } 832ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim return false; 842ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim } 852ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim 867fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processAllMessages() { 87964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Use the copied buffer. 88964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer); 89964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 90964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (HdmiCecMessage message : copiedBuffer) { 917fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDevice.onMessage(message); 927fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiLogger.debug("Processing message:" + message); 937fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 947fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 957fa3a66470d2133796defd14a0600578758882acJinsuk Kim 967fa3a66470d2133796defd14a0600578758882acJinsuk Kim /** 977fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Process messages from a given logical device. Called by 987fa3a66470d2133796defd14a0600578758882acJinsuk Kim * {@link NewDeviceAction} actions when they finish adding the device 997fa3a66470d2133796defd14a0600578758882acJinsuk Kim * information. 1006e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * <p><Active Source> is processed only when the TV input is ready. 1016e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * If not, {@link #processActiveSource()} will be invoked later to handle it. 1027fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 1037fa3a66470d2133796defd14a0600578758882acJinsuk Kim * @param address logical address of CEC device which the messages to process 1047fa3a66470d2133796defd14a0600578758882acJinsuk Kim * are associated with 1057fa3a66470d2133796defd14a0600578758882acJinsuk Kim */ 1067fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processMessagesForDevice(int address) { 107964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer); 108964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 1096e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim HdmiLogger.debug("Checking message for address:" + address); 110964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (HdmiCecMessage message : copiedBuffer) { 111964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (message.getSource() != address) { 112964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 113964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim continue; 114964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 1156e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE 116964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim && !mDevice.isInputReady(HdmiDeviceInfo.idForCecDevice(address))) { 117964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 118964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim continue; 119964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 1206e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mDevice.onMessage(message); 1216e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim HdmiLogger.debug("Processing message:" + message); 1227fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1237fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1247fa3a66470d2133796defd14a0600578758882acJinsuk Kim 1257fa3a66470d2133796defd14a0600578758882acJinsuk Kim /** 1267fa3a66470d2133796defd14a0600578758882acJinsuk Kim * Process <Active Source>. 1277fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 1287fa3a66470d2133796defd14a0600578758882acJinsuk Kim * <p>The message has a dependency on TV input framework. Should be invoked 1297fa3a66470d2133796defd14a0600578758882acJinsuk Kim * after we get the callback 1307fa3a66470d2133796defd14a0600578758882acJinsuk Kim * {@link android.media.tv.TvInputManager.TvInputCallback#onInputAdded(String)} 1317fa3a66470d2133796defd14a0600578758882acJinsuk Kim * to ensure the processing of the message takes effect when transformed 1327fa3a66470d2133796defd14a0600578758882acJinsuk Kim * to input change callback. 1337fa3a66470d2133796defd14a0600578758882acJinsuk Kim * 1347fa3a66470d2133796defd14a0600578758882acJinsuk Kim * @param address logical address of the device to be the active source 1357fa3a66470d2133796defd14a0600578758882acJinsuk Kim */ 1367fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processActiveSource(int address) { 137964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer); 138964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 139964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (HdmiCecMessage message : copiedBuffer) { 1407fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE 1417fa3a66470d2133796defd14a0600578758882acJinsuk Kim && message.getSource() == address) { 1427fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDevice.onMessage(message); 1437fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiLogger.debug("Processing message:" + message); 144964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } else { 145964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 1467fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1477fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1487fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1497fa3a66470d2133796defd14a0600578758882acJinsuk Kim} 150