1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.hdmi;
18 
19 import android.hardware.hdmi.HdmiDeviceInfo;
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 
23 /**
24  * Buffer storage to keep incoming messages for later processing. Used to
25  * handle messages that arrive when the device is not ready. Useful when
26  * keeping the messages from a connected device which are not discovered yet.
27  */
28 final class DelayedMessageBuffer {
29     private final ArrayList<HdmiCecMessage> mBuffer = new ArrayList<>();
30     private final HdmiCecLocalDevice mDevice;
31 
DelayedMessageBuffer(HdmiCecLocalDevice device)32     DelayedMessageBuffer(HdmiCecLocalDevice device) {
33         mDevice = device;
34     }
35 
36     /**
37      * Add a new message to the buffer. The buffer keeps selected messages in
38      * the order they are received.
39      *
40      * @param message {@link HdmiCecMessage} to add
41      */
add(HdmiCecMessage message)42     void add(HdmiCecMessage message) {
43         boolean buffered = true;
44 
45         // Note that all the messages are not handled in the same manner.
46         // For &lt;Active Source&gt; we keep the latest one only.
47         // TODO: This might not be the best way to choose the active source.
48         //       Devise a better way to pick up the best one.
49         switch (message.getOpcode()) {
50             case Constants.MESSAGE_ACTIVE_SOURCE:
51                 removeActiveSource();
52                 mBuffer.add(message);
53                 break;
54             case Constants.MESSAGE_INITIATE_ARC:
55             case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE:
56                 mBuffer.add(message);
57                 break;
58             default:
59                 buffered = false;
60                 break;
61         }
62         if (buffered) {
63             HdmiLogger.debug("Buffering message:" + message);
64         }
65     }
66 
removeActiveSource()67     private void removeActiveSource() {
68         // Uses iterator to remove elements while looping through the list.
69         for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) {
70             HdmiCecMessage message = iter.next();
71             if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE) {
72                 iter.remove();
73             }
74         }
75     }
76 
isBuffered(int opcode)77     boolean isBuffered(int opcode) {
78         for (HdmiCecMessage message : mBuffer) {
79             if (message.getOpcode() == opcode) {
80                 return true;
81             }
82         }
83         return false;
84     }
85 
processAllMessages()86     void processAllMessages() {
87         // Use the copied buffer.
88         ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<>(mBuffer);
89         mBuffer.clear();
90         for (HdmiCecMessage message : copiedBuffer) {
91             mDevice.onMessage(message);
92             HdmiLogger.debug("Processing message:" + message);
93         }
94     }
95 
96     /**
97      * Process messages from a given logical device. Called by
98      * {@link NewDeviceAction} actions when they finish adding the device
99      * information.
100      * <p>&lt;Active Source&gt; is processed only when the TV input is ready.
101      * If not, {@link #processActiveSource()} will be invoked later to handle it.
102      *
103      * @param address logical address of CEC device which the messages to process
104      *        are associated with
105      */
processMessagesForDevice(int address)106     void processMessagesForDevice(int address) {
107         ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<>(mBuffer);
108         mBuffer.clear();
109         HdmiLogger.debug("Checking message for address:" + address);
110         for (HdmiCecMessage message : copiedBuffer) {
111             if (message.getSource() != address) {
112                 mBuffer.add(message);
113                 continue;
114             }
115             if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
116                     && !mDevice.isInputReady(HdmiDeviceInfo.idForCecDevice(address))) {
117                 mBuffer.add(message);
118                 continue;
119             }
120             mDevice.onMessage(message);
121             HdmiLogger.debug("Processing message:" + message);
122         }
123     }
124 
125     /**
126      * Process &lt;Active Source&gt;.
127      *
128      * <p>The message has a dependency on TV input framework. Should be invoked
129      * after we get the callback
130      * {@link android.media.tv.TvInputManager.TvInputCallback#onInputAdded(String)}
131      * to ensure the processing of the message takes effect when transformed
132      * to input change callback.
133      *
134      * @param address logical address of the device to be the active source
135      */
processActiveSource(int address)136     void processActiveSource(int address) {
137         ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<>(mBuffer);
138         mBuffer.clear();
139         for (HdmiCecMessage message : copiedBuffer) {
140             if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
141                     && message.getSource() == address) {
142                 mDevice.onMessage(message);
143                 HdmiLogger.debug("Processing message:" + message);
144             } else {
145                 mBuffer.add(message);
146             }
147         }
148     }
149 }
150