diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java index 7d15f4cb24d1d..b7b2f90be984b 100644 --- a/services/core/java/com/android/server/hdmi/FeatureAction.java +++ b/services/core/java/com/android/server/hdmi/FeatureAction.java @@ -18,11 +18,13 @@ package com.android.server.hdmi; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; +import java.util.ArrayList; import java.util.List; /** @@ -59,6 +61,8 @@ abstract class FeatureAction { // Timer that manages timeout events. protected ActionTimer mActionTimer; + private ArrayList> mOnFinishedCallbacks; + FeatureAction(HdmiCecLocalDevice source) { mSource = source; mService = mSource.getService(); @@ -220,8 +224,22 @@ abstract class FeatureAction { * Finish up the action. Reset the state, and remove itself from the action queue. */ protected void finish() { + finish(true); + } + + void finish(boolean removeSelf) { clear(); - removeAction(this); + if (removeSelf) { + removeAction(this); + } + if (mOnFinishedCallbacks != null) { + for (Pair actionCallbackPair: mOnFinishedCallbacks) { + if (actionCallbackPair.first.mState != STATE_NONE) { + actionCallbackPair.second.run(); + } + } + mOnFinishedCallbacks = null; + } } protected final HdmiCecLocalDevice localDevice() { @@ -244,10 +262,17 @@ abstract class FeatureAction { return mSource.getDeviceInfo().getPhysicalAddress(); } - protected void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) { + protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) { sendCommand(HdmiCecMessageBuilder.buildUserControlPressed( getSourceAddress(), targetAddress, uiCommand)); sendCommand(HdmiCecMessageBuilder.buildUserControlReleased( getSourceAddress(), targetAddress)); } + + protected final void addOnFinishedCallback(FeatureAction action, Runnable runnable) { + if (mOnFinishedCallbacks == null) { + mOnFinishedCallbacks = new ArrayList<>(); + } + mOnFinishedCallbacks.add(Pair.create(action, runnable)); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 3937ce1010e8e..7515242379a50 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -65,7 +65,7 @@ abstract class HdmiCecLocalDevice { // Note that access to this collection should happen in service thread. private final LinkedList mActions = new LinkedList<>(); - private Handler mHandler = new Handler () { + private final Handler mHandler = new Handler () { @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -482,6 +482,7 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly void removeAction(final FeatureAction action) { assertRunOnServiceThread(); + action.finish(false); mActions.remove(action); checkIfPendingActionsCleared(); } @@ -502,8 +503,8 @@ abstract class HdmiCecLocalDevice { while (iter.hasNext()) { FeatureAction action = iter.next(); if (action != exception && action.getClass().equals(clazz)) { - action.clear(); - mActions.remove(action); + action.finish(false); + iter.remove(); } } checkIfPendingActionsCleared(); @@ -637,7 +638,7 @@ abstract class HdmiCecLocalDevice { Iterator iter = mActions.iterator(); while (iter.hasNext()) { FeatureAction action = iter.next(); - action.finish(); + action.finish(false); iter.remove(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 923b87d4ce560..8840c6268922f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -536,10 +536,17 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @ServiceThreadOnly + // Seq #32 void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) { assertRunOnServiceThread(); + if (!mService.isControlEnabled() || hasAction(DeviceDiscoveryAction.class)) { + setSystemAudioMode(false, true); + invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); + return; + } HdmiCecDeviceInfo avr = getAvrDeviceInfo(); if (avr == null) { + setSystemAudioMode(false, true); invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); return; } diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java index 185de59f1c15a..6204c169d1aa3 100644 --- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java +++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java @@ -219,7 +219,7 @@ final class HotplugDetectionAction extends FeatureAction { return; } - // Should ave only one Device Select Action + // Should have only one Device Select Action DeviceSelectAction action = actions.get(0); if (action.getTargetAddress() == address) { removeAction(DeviceSelectAction.class); diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index 86895cc9651de..4be036a3d2ef9 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -23,14 +23,20 @@ import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; +import java.util.List; + /** * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr. */ abstract class SystemAudioAction extends FeatureAction { private static final String TAG = "SystemAudioAction"; + // Transient state to differentiate with STATE_NONE where the on-finished callback + // will not be called. + private static final int STATE_CHECK_ROUTING_IN_PRGRESS = 1; + // State in which waits for . - private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1; + private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 2; private static final int MAX_SEND_RETRY_COUNT = 2; @@ -65,7 +71,25 @@ abstract class SystemAudioAction extends FeatureAction { mCallback = callback; } + // Seq #27 protected void sendSystemAudioModeRequest() { + mState = STATE_CHECK_ROUTING_IN_PRGRESS; + List routingActions = getActions(RoutingControlAction.class); + if (!routingActions.isEmpty()) { + // Should have only one Routing Control Action + RoutingControlAction routingAction = routingActions.get(0); + routingAction.addOnFinishedCallback(this, new Runnable() { + @Override + public void run() { + sendSystemAudioModeRequestInternal(); + } + }); + return; + } + sendSystemAudioModeRequestInternal(); + } + + private void sendSystemAudioModeRequestInternal() { int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress(); HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest( getSourceAddress(), diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java index a56507762321f..77783b71ee494 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java @@ -23,7 +23,7 @@ import android.hardware.hdmi.IHdmiControlCallback; /** * Feature action that handles System Audio initiated by AVR devices. */ -// # Seq 33 +// Seq #33 final class SystemAudioActionFromAvr extends SystemAudioAction { /** * Constructor diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java index 2146c4ef3e494..cb3588c79f487 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java @@ -24,6 +24,7 @@ import android.hardware.hdmi.IHdmiControlCallback; * Feature action that handles System Audio initiated by TV devices. */ final class SystemAudioActionFromTv extends SystemAudioAction { + /** * Constructor * @@ -41,9 +42,6 @@ final class SystemAudioActionFromTv extends SystemAudioAction { @Override boolean start() { - // TODO: Check HDMI-CEC is enabled. - // TODO: Move to the waiting state if currently a routing change is in progress. - removeSystemAudioActionInProgress(); sendSystemAudioModeRequest(); return true; diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java index 80954d4c5fbf1..d03634ec951a8 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java @@ -21,6 +21,7 @@ import com.android.server.hdmi.HdmiControlService.SendMessageCallback; /** * Action to initiate system audio once AVR is detected on Device discovery action. */ +// Seq #27 final class SystemAudioAutoInitiationAction extends FeatureAction { private final int mAvrAddress;