Enable all actions to have chance to consume incoming message.

Some actions such as "DevicePowerStatusAction", "PowerStatusMonitorAction",
"Routing Contron Action" might wait for receiving <Report Power Status>
message, but the oldest aciton, which is normally PowerStatusMonitorAction,
can consume it.
This change enables all actions to have chance to touch incoming message.

Along with this, it fixes audio mute bug during volume control.

Bug: 17597377
Change-Id: Iafb71f6ea6309a4fba79833da2d634222058ac78
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index d965caa..3dd1522 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -70,7 +70,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+               || mTargetAddress != cmd.getSource()) {
             return false;
         }
         if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index d155e84..4d92686 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -95,7 +95,7 @@
         sendCommand(mGivePowerStatus, new SendMessageCallback() {
             @Override
             public void onSendCompleted(int error) {
-                if (error == Constants.SEND_RESULT_NAK) {
+                if (error != Constants.SEND_RESULT_SUCCESS) {
                     invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
                     finish();
                     return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index b2300a6..c47e0e9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -84,8 +84,7 @@
      * Process the command. Called whenever a new command arrives.
      *
      * @param cmd command to process
-     * @return true if the command was consumed in the process; Otherwise false, which
-     *          indicates that the command shall be handled by other actions.
+     * @return true if the command was consumed in the process; Otherwise false.
      */
     abstract boolean processCommand(HdmiCecMessage cmd);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 41ac589..9273cb6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -34,7 +34,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -125,7 +124,7 @@
 
     // A collection of FeatureAction.
     // Note that access to this collection should happen in service thread.
-    private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>();
+    private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>();
 
     private final Handler mHandler = new Handler () {
         @Override
@@ -290,12 +289,14 @@
     @ServiceThreadOnly
     private boolean dispatchMessageToAction(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        for (HdmiCecFeatureAction action : mActions) {
-            if (action.processCommand(message)) {
-                return true;
-            }
+        boolean processed = false;
+        // Use copied action list in that processCommand may remove itself.
+        for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
+            // Iterates all actions to check whether incoming message is consumed.
+            boolean result = action.processCommand(message);
+            processed = processed || result;
         }
-        return false;
+        return processed;
     }
 
     @ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 7db991a..e764a1c 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -92,7 +92,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+        if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+                || mTargetAddress != cmd.getSource()) {
             return false;
         }
         if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index 39c0d7f..906944b 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -68,23 +68,21 @@
                             finish();
                             return;
                         }
-
-                        mState = STATE_WAITING_FOR_RECORD_STATUS;
-                        addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
                     }
                 });
+        mState = STATE_WAITING_FOR_RECORD_STATUS;
+        addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
     }
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_RECORD_STATUS) {
+        if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) {
             return false;
         }
 
         switch (cmd.getOpcode()) {
             case Constants.MESSAGE_RECORD_STATUS:
                 return handleRecordStatus(cmd);
-
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 0871194..6023354 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -125,6 +125,9 @@
 
     @Override
     final boolean processCommand(HdmiCecMessage cmd) {
+        if (cmd.getSource() != mAvrLogicalAddress) {
+            return false;
+        }
         switch (mState) {
             case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
                 if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 3653aac..50f8475 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -58,17 +58,16 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) {
+        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS
+                || mAvrAddress != cmd.getSource()) {
             return false;
         }
 
-        switch (cmd.getOpcode()) {
-            case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
-                handleSystemAudioModeStatusMessage();
-                return true;
-            default:
-                return false;
+        if (cmd.getOpcode() == Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS) {
+            handleSystemAudioModeStatusMessage();
+            return true;
         }
+        return false;
     }
 
     private void handleSystemAudioModeStatusMessage() {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index bfcda50..dba3591 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -79,7 +79,7 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
+        if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS || mAvrAddress != cmd.getSource()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 8fc0182..5fcbc91 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -96,11 +96,8 @@
 
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
-        if (mState != STATE_WAITING_FOR_TIMER_STATUS) {
-            return false;
-        }
-
-        if (cmd.getSource() != mRecorderAddress) {
+        if (mState != STATE_WAITING_FOR_TIMER_STATUS
+                || cmd.getSource() != mRecorderAddress) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index 4338fc7..f1a9a5c 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -45,6 +45,7 @@
     private boolean mIsVolumeUp;
     private long mLastKeyUpdateTime;
     private int mLastAvrVolume;
+    private boolean mLastAvrMute;
     private boolean mSentKeyPressed;
 
     /**
@@ -74,6 +75,7 @@
         mAvrAddress = avrAddress;
         mIsVolumeUp = isVolumeUp;
         mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+        mLastAvrMute = false;
         mSentKeyPressed = false;
 
         updateLastKeyUpdateTime();
@@ -108,6 +110,8 @@
             HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp);
             sendVolumeKeyReleased();
             mIsVolumeUp = isVolumeUp;
+            sendVolumeKeyPressed();
+            resetTimer();
         }
         updateLastKeyUpdateTime();
     }
@@ -129,9 +133,8 @@
                 return handleReportAudioStatus(cmd);
             case MESSAGE_FEATURE_ABORT:
                 return handleFeatureAbort(cmd);
-            default:
-                return false;
         }
+        return false;
     }
 
     private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
@@ -139,9 +142,12 @@
         boolean mute = (params[0] & 0x80) == 0x80;
         int volume = params[0] & 0x7F;
         mLastAvrVolume = volume;
+        mLastAvrMute = mute;
         if (shouldUpdateAudioVolume(mute)) {
             HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume);
             tv().setAudioStatus(mute, volume);
+            mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+            mLastAvrMute = false;
         }
         return true;
     }
@@ -182,8 +188,9 @@
             sendVolumeKeyReleased();
         }
         if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) {
-            tv().setAudioStatus(false, mLastAvrVolume);
+            tv().setAudioStatus(mLastAvrMute, mLastAvrVolume);
             mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+            mLastAvrMute = false;
         }
     }