diff options
| author | Jungshik Jang <jayjang@google.com> | 2014-06-17 04:05:37 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-06-17 04:00:08 +0000 |
| commit | 3e1e33f13b524b26188dd4a97469ce21518c8d0d (patch) | |
| tree | 343e40be5b18d078f1132d3a07114bf239666c5d /services/core | |
| parent | 28b244ef024269cffbbc93b1ae3a53e576ba16b8 (diff) | |
| parent | 79c58a4b97f27ede6a1b680d2fece9c2a0edf7b7 (diff) | |
| download | frameworks_base-3e1e33f13b524b26188dd4a97469ce21518c8d0d.zip frameworks_base-3e1e33f13b524b26188dd4a97469ce21518c8d0d.tar.gz frameworks_base-3e1e33f13b524b26188dd4a97469ce21518c8d0d.tar.bz2 | |
Merge "Rearrange ownership between Hdmi control modules."
Diffstat (limited to 'services/core')
24 files changed, 912 insertions, 748 deletions
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index bcd08ebf..23cf40b 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -26,31 +26,29 @@ import android.util.Slog; /** * Handles CEC command <Active Source>. - * - * <p>Used by feature actions that need to handle the command in their flow. + * <p> + * Used by feature actions that need to handle the command in their flow. */ final class ActiveSourceHandler { private static final String TAG = "ActiveSourceHandler"; + private final HdmiCecLocalDevice mSource; private final HdmiControlService mService; - private final int mSourceAddress; - private final int mSourcePath; - @Nullable private final IHdmiControlCallback mCallback; + @Nullable + private final IHdmiControlCallback mCallback; - static ActiveSourceHandler create(HdmiControlService service, int sourceAddress, - int sourcePath, IHdmiControlCallback callback) { - if (service == null) { + static ActiveSourceHandler create(HdmiCecLocalDevice source, + IHdmiControlCallback callback) { + if (source == null) { Slog.e(TAG, "Wrong arguments"); return null; } - return new ActiveSourceHandler(service, sourceAddress, sourcePath, callback); + return new ActiveSourceHandler(source, callback); } - private ActiveSourceHandler(HdmiControlService service, int sourceAddress, int sourcePath, - IHdmiControlCallback callback) { - mService = service; - mSourceAddress = sourceAddress; - mSourcePath = sourcePath; + private ActiveSourceHandler(HdmiCecLocalDevice source, IHdmiControlCallback callback) { + mSource = source; + mService = mSource.getService(); mCallback = callback; } @@ -61,7 +59,7 @@ final class ActiveSourceHandler { * @param routingPath routing path of the device to be the active source */ void process(int deviceLogicalAddress, int routingPath) { - if (mSourcePath == routingPath && mService.getActiveSource() == mSourceAddress) { + if (getSourcePath() == routingPath && mSource.getActiveSource() == getSourceAddress()) { invokeCallback(HdmiCec.RESULT_SUCCESS); return; } @@ -69,14 +67,14 @@ final class ActiveSourceHandler { if (device == null) { // "New device action" initiated by <Active Source> does not require // "Routing change action". - mService.addAndStartAction(new NewDeviceAction(mService, mSourceAddress, - deviceLogicalAddress, routingPath, false)); + mSource.addAndStartAction(new NewDeviceAction(mSource, deviceLogicalAddress, + routingPath, false)); } - if (!mService.isInPresetInstallationMode()) { - int prevActiveInput = mService.getActiveInput(); - mService.updateActiveDevice(deviceLogicalAddress, routingPath); - if (prevActiveInput != mService.getActiveInput()) { + if (!mSource.isInPresetInstallationMode()) { + int prevActiveInput = mSource.getActiveInput(); + mSource.updateActiveDevice(deviceLogicalAddress, routingPath); + if (prevActiveInput != mSource.getActiveInput()) { // TODO: change port input here. } invokeCallback(HdmiCec.RESULT_SUCCESS); @@ -84,24 +82,33 @@ final class ActiveSourceHandler { // TV is in a mode that should keep its current source/input from // being changed for its operation. Reclaim the active source // or switch the port back to the one used for the current mode. - if (mService.getActiveSource() == mSourceAddress) { + if (mSource.getActiveSource() == getSourceAddress()) { HdmiCecMessage activeSource = - HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath); + HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), + getSourcePath()); mService.sendCecCommand(activeSource); - mService.updateActiveDevice(deviceLogicalAddress, routingPath); + mSource.updateActiveDevice(deviceLogicalAddress, routingPath); invokeCallback(HdmiCec.RESULT_SUCCESS); } else { - int activePath = mService.getActivePath(); - mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(mSourceAddress, + int activePath = mSource.getActivePath(); + mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(), routingPath, activePath)); // TODO: Start port select action here - // PortSelectAction action = new PortSelectAction(mService, mSourceAddress, - // activePath, mCallback); + // PortSelectAction action = new PortSelectAction(mService, getSourceAddress(), + // activePath, mCallback); // mService.addActionAndStart(action); } } } + private final int getSourceAddress() { + return mSource.getDeviceInfo().getLogicalAddress(); + } + + private final int getSourcePath() { + return mSource.getDeviceInfo().getPhysicalAddress(); + } + private void invokeCallback(int result) { if (mCallback == null) { return; diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java index f7392e9..daeff3c 100644 --- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java @@ -94,12 +94,10 @@ final class DeviceDiscoveryAction extends FeatureAction { /** * Constructor. * - * @param service an instance of {@link HdmiControlService}. - * @param sourceAddress a logical address which initiates this action + * @param source an instance of {@link HdmiCecLocalDevice}. */ - DeviceDiscoveryAction(HdmiControlService service, int sourceAddress, - DeviceDiscoveryCallback callback) { - super(service, sourceAddress); + DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) { + super(source); mCallback = Preconditions.checkNotNull(callback); } @@ -108,7 +106,7 @@ final class DeviceDiscoveryAction extends FeatureAction { mDevices.clear(); mState = STATE_WAITING_FOR_DEVICE_POLLING; - mService.pollDevices(new DevicePollingCallback() { + pollDevices(new DevicePollingCallback() { @Override public void onPollingFinished(List<Integer> ackedAddress) { if (ackedAddress.isEmpty()) { @@ -156,7 +154,7 @@ final class DeviceDiscoveryAction extends FeatureAction { if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS)) { return; } - sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, address)); + sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), address)); addTimer(mState, TIMEOUT_MS); } @@ -179,7 +177,7 @@ final class DeviceDiscoveryAction extends FeatureAction { if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_SET_OSD_NAME)) { return; } - sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, address)); + sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(), address)); addTimer(mState, TIMEOUT_MS); } @@ -203,12 +201,13 @@ final class DeviceDiscoveryAction extends FeatureAction { if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) { return; } - sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, address)); + sendCommand( + HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(), address)); addTimer(mState, TIMEOUT_MS); } private boolean mayProcessMessageIfCached(int address, int opcode) { - HdmiCecMessage message = mService.getCecMessageCache().getMessage(address, opcode); + HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode); if (message != null) { processCommand(message); return true; diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java index 63c2182..51df473 100644 --- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java +++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java @@ -16,9 +16,10 @@ package com.android.server.hdmi; * limitations under the License. */ -import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; @@ -40,18 +41,18 @@ final class DevicePowerStatusAction extends FeatureAction { private final int mTargetAddress; private final IHdmiControlCallback mCallback; - static DevicePowerStatusAction create(HdmiControlService service, int sourceAddress, + static DevicePowerStatusAction create(HdmiCecLocalDevice source, int targetAddress, IHdmiControlCallback callback) { - if (service == null || callback == null) { + if (source == null || callback == null) { Slog.e(TAG, "Wrong arguments"); return null; } - return new DevicePowerStatusAction(service, sourceAddress, targetAddress, callback); + return new DevicePowerStatusAction(source, targetAddress, callback); } - private DevicePowerStatusAction(HdmiControlService service, int sourceAddress, + private DevicePowerStatusAction(HdmiCecLocalDevice localDevice, int targetAddress, IHdmiControlCallback callback) { - super(service, sourceAddress); + super(localDevice); mTargetAddress = targetAddress; mCallback = callback; } @@ -65,8 +66,8 @@ final class DevicePowerStatusAction extends FeatureAction { } private void queryDevicePowerStatus() { - mService.sendCecCommand( - HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress)); + sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), + mTargetAddress)); } @Override diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index a8696a1..dbe3b80 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -16,10 +16,11 @@ package com.android.server.hdmi; -import android.hardware.hdmi.IHdmiControlCallback; -import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.HdmiTvClient; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; @@ -66,24 +67,20 @@ final class DeviceSelectAction extends FeatureAction { private final HdmiCecDeviceInfo mTarget; private final IHdmiControlCallback mCallback; - private final int mSourcePath; private int mPowerStatusCounter = 0; /** * Constructor. * - * @param service {@link HdmiControlService} instance - * @param sourceAddress logical address of TV initiating this action - * @param sourcePath physical address of TV + * @param source {@link HdmiCecLocalDevice} instance * @param target target logical device that will be a new active source * @param callback callback object */ - public DeviceSelectAction(HdmiControlService service, int sourceAddress, int sourcePath, + public DeviceSelectAction(HdmiCecLocalDevice source, HdmiCecDeviceInfo target, IHdmiControlCallback callback) { - super(service, sourceAddress); + super(source); mCallback = callback; - mSourcePath = sourcePath; mTarget = target; } @@ -96,7 +93,7 @@ final class DeviceSelectAction extends FeatureAction { private void queryDevicePowerStatus() { sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus( - mSourceAddress, mTarget.getLogicalAddress())); + getSourceAddress(), mTarget.getLogicalAddress())); mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; addTimer(mState, TIMEOUT_MS); } @@ -118,7 +115,8 @@ final class DeviceSelectAction extends FeatureAction { case STATE_WAIT_FOR_ACTIVE_SOURCE: if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) { int activePath = HdmiUtils.twoBytesToInt(params); - ActiveSourceHandler.create(mService, mSourceAddress, mSourcePath, mCallback) + ActiveSourceHandler + .create(localDevice(), mCallback) .process(cmd.getSource(), activePath); finish(); return true; @@ -174,15 +172,15 @@ final class DeviceSelectAction extends FeatureAction { private void sendSetStreamPath() { sendCommand(HdmiCecMessageBuilder.buildSetStreamPath( - mSourceAddress, mTarget.getPhysicalAddress())); + getSourceAddress(), mTarget.getPhysicalAddress())); mState = STATE_WAIT_FOR_ACTIVE_SOURCE; addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS); } private void sendRemoteKeyCommand(int keyCode) { - sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(mSourceAddress, + sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), mTarget.getLogicalAddress(), keyCode)); - sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(mSourceAddress, + sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(), mTarget.getLogicalAddress())); } diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java index ae272b4..0ec17f6 100644 --- a/services/core/java/com/android/server/hdmi/FeatureAction.java +++ b/services/core/java/com/android/server/hdmi/FeatureAction.java @@ -22,6 +22,9 @@ import android.os.Message; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; + +import java.util.List; /** * Encapsulates a sequence of CEC/MHL command exchange for a certain feature. @@ -33,14 +36,13 @@ import com.android.internal.annotations.VisibleForTesting; * of the object. All the actual action classes inherit FeatureAction. * * <p>More than one FeatureAction objects can be up and running simultaneously, - * maintained by {@link HdmiControlService}. Each action is passed a new command + * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command * arriving from the bus, and either consumes it if the command is what the action expects, * or yields it to other action. * * Declared as package private, accessed by {@link HdmiControlService} only. */ abstract class FeatureAction { - private static final String TAG = "FeatureAction"; // Timer handler message used for timeout event @@ -56,19 +58,16 @@ abstract class FeatureAction { // Internal state indicating the progress of action. protected int mState = STATE_NONE; - protected final HdmiControlService mService; - - // Logical address of the device for which the feature action is taken. The commands - // generated in an action all use this field as source address. - protected final int mSourceAddress; + private final HdmiControlService mService; + private final HdmiCecLocalDevice mSource; // Timer that manages timeout events. protected ActionTimer mActionTimer; - FeatureAction(HdmiControlService service, int sourceAddress) { - mService = service; - mSourceAddress = sourceAddress; - mActionTimer = createActionTimer(service.getServiceLooper()); + FeatureAction(HdmiCecLocalDevice source) { + mSource = source; + mService = mSource.getService(); + mActionTimer = createActionTimer(mService.getServiceLooper()); } @VisibleForTesting @@ -175,6 +174,42 @@ abstract class FeatureAction { mService.sendCecCommand(cmd, callback); } + protected final void addAndStartAction(FeatureAction action) { + mSource.addAndStartAction(action); + } + + protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) { + return mSource.getActions(clazz); + } + + protected final HdmiCecMessageCache getCecMessageCache() { + return mSource.getCecMessageCache(); + } + + /** + * Remove the action from the action queue. This is called after the action finishes + * its role. + * + * @param action + */ + protected final void removeAction(FeatureAction action) { + mSource.removeAction(action); + } + + protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) { + mSource.removeActionExcept(clazz, null); + } + + protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz, + final FeatureAction exception) { + mSource.removeActionExcept(clazz, exception); + } + + protected final void pollDevices(DevicePollingCallback callback, int pickStrategy, + int retryCount) { + mService.pollDevices(callback, pickStrategy, retryCount); + } + /** * Clean up action's state. * @@ -194,13 +229,23 @@ abstract class FeatureAction { removeAction(this); } - /** - * Remove the action from the action queue. This is called after the action finishes - * its role. - * - * @param action - */ - private void removeAction(FeatureAction action) { - mService.removeAction(action); + protected final HdmiCecLocalDevice localDevice() { + return mSource; + } + + protected final HdmiCecLocalDevicePlayback playback() { + return (HdmiCecLocalDevicePlayback) mSource; + } + + protected final HdmiCecLocalDeviceTv tv() { + return (HdmiCecLocalDeviceTv) mSource; + } + + protected final int getSourceAddress() { + return mSource.getDeviceInfo().getLogicalAddress(); + } + + protected final int getSourcePath() { + return mSource.getDeviceInfo().getPhysicalAddress(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index a0c635d..fe16869 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -17,7 +17,6 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; -import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; import android.hardware.hdmi.HdmiPortInfo; import android.os.Handler; @@ -109,10 +108,6 @@ final class HdmiCecController { private HdmiControlService mService; - // Map-like container of all cec devices including local ones. - // A logical address of device is used as key of container. - private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>(); - // Stores the local CEC devices in the system. Device type is used for key. private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>(); @@ -224,90 +219,6 @@ final class HdmiCecController { return body; } - /** - * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same - * logical address as new device info's. - * - * <p>Declared as package-private. accessed by {@link HdmiControlService} only. - * - * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added. - * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo} - * that has the same logical address as new one has. - */ - HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) { - assertRunOnServiceThread(); - HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress()); - if (oldDeviceInfo != null) { - removeDeviceInfo(deviceInfo.getLogicalAddress()); - } - mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo); - return oldDeviceInfo; - } - - /** - * Remove a device info corresponding to the given {@code logicalAddress}. - * It returns removed {@link HdmiCecDeviceInfo} if exists. - * - * <p>Declared as package-private. accessed by {@link HdmiControlService} only. - * - * @param logicalAddress logical address of device to be removed - * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null} - */ - HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) { - assertRunOnServiceThread(); - HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress); - if (deviceInfo != null) { - mDeviceInfos.remove(logicalAddress); - } - return deviceInfo; - } - - /** - * Clear all device info. - * - * <p>Declared as package-private. accessed by {@link HdmiControlService} only. - */ - void clearDeviceInfoList() { - assertRunOnServiceThread(); - mDeviceInfos.clear(); - } - - /** - * Return a list of all {@link HdmiCecDeviceInfo}. - * - * <p>Declared as package-private. accessed by {@link HdmiControlService} only. - * - * @param includeLocalDevice whether to add local device or not - */ - List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) { - assertRunOnServiceThread(); - if (includeLocalDevice) { - return sparseArrayToList(mDeviceInfos); - } else { - ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>(); - for (int i = 0; i < mDeviceInfos.size(); ++i) { - HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i); - if (mRemoteDeviceAddressPredicate.apply(info.getLogicalAddress())) { - infoList.add(info); - } - } - return infoList; - } - } - - /** - * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}. - * - * <p>Declared as package-private. accessed by {@link HdmiControlService} only. - * - * @param logicalAddress logical address to be retrieved - * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}. - * Returns null if no logical address matched - */ - HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { - assertRunOnServiceThread(); - return mDeviceInfos.get(logicalAddress); - } HdmiPortInfo[] getPortInfos() { return nativeGetPortInfos(mNativePtr); @@ -451,7 +362,7 @@ final class HdmiCecController { */ List<HdmiCecLocalDevice> getLocalDeviceList() { assertRunOnServiceThread(); - return sparseArrayToList(mLocalDevices); + return HdmiUtils.sparseArrayToList(mLocalDevices); } private List<Integer> pickPollCandidates(int pickStrategy) { @@ -489,14 +400,6 @@ final class HdmiCecController { return pollingCandidates; } - private static <T> List<T> sparseArrayToList(SparseArray<T> array) { - ArrayList<T> list = new ArrayList<>(); - for (int i = 0; i < array.size(); ++i) { - list.add(array.valueAt(i)); - } - return list; - } - private boolean isAllocatedLocalDeviceAddress(int address) { for (int i = 0; i < mLocalDevices.size(); ++i) { if (mLocalDevices.valueAt(i).isAddressOf(address)) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 7a2a6cc..08d7786 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -19,8 +19,16 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.os.Looper; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + /** * Class that models a logical CEC device hosted in this system. Handles initialization, * CEC commands that call for actions customized per device type. @@ -34,10 +42,37 @@ abstract class HdmiCecLocalDevice { protected int mPreferredAddress; protected HdmiCecDeviceInfo mDeviceInfo; + // Logical address of the active source. + @GuardedBy("mLock") + private int mActiveSource; + + // Active routing path. Physical address of the active source but not all the time, such as + // when the new active source does not claim itself to be one. Note that we don't keep + // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}. + @GuardedBy("mLock") + private int mActiveRoutingPath; + + // Set to true while the service is in normal mode. While set to false, no input change is + // allowed. Used for situations where input change can confuse users such as channel auto-scan, + // system upgrade, etc., a.k.a. "prohibit mode". + @GuardedBy("mLock") + private boolean mInputChangeEnabled; + + protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache(); + protected final Object mLock; + + // A collection of FeatureAction. + // Note that access to this collection should happen in service thread. + private final LinkedList<FeatureAction> mActions = new LinkedList<>(); + protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) { mService = service; mDeviceType = deviceType; mAddress = HdmiCec.ADDR_UNREGISTERED; + mLock = service.getServiceLock(); + + // TODO: Get control flag from persistent storage + mInputChangeEnabled = true; } // Factory method that returns HdmiCecLocalDevice of corresponding type. @@ -69,14 +104,23 @@ abstract class HdmiCecLocalDevice { * @return true if consumed a message; otherwise, return false. */ final boolean dispatchMessage(HdmiCecMessage message) { + assertRunOnServiceThread(); + int dest = message.getDestination(); if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) { return false; } + // Cache incoming message. Note that it caches only white-listed one. + mCecMessageCache.cacheMessage(message); return onMessage(message); } protected final boolean onMessage(HdmiCecMessage message) { + assertRunOnServiceThread(); + + if (dispatchMessageToAction(message)) { + return true; + } switch (message.getOpcode()) { case HdmiCec.MESSAGE_GET_MENU_LANGUAGE: return handleGetMenuLanguage(message); @@ -90,12 +134,31 @@ abstract class HdmiCecLocalDevice { return handleGetCecVersion(message); case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS: return handleReportPhysicalAddress(message); + case HdmiCec.MESSAGE_INITIATE_ARC: + return handleInitiateArc(message); + case HdmiCec.MESSAGE_TERMINATE_ARC: + return handleTerminateArc(message); + case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE: + return handleSetSystemAudioMode(message); + case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: + return handleSystemAudioModeStatus(message); default: return false; } } + private boolean dispatchMessageToAction(HdmiCecMessage message) { + for (FeatureAction action : mActions) { + if (action.processCommand(message)) { + return true; + } + } + return false; + } + protected boolean handleGivePhysicalAddress() { + assertRunOnServiceThread(); + int physicalAddress = mService.getPhysicalAddress(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, physicalAddress, mDeviceType); @@ -104,6 +167,8 @@ abstract class HdmiCecLocalDevice { } protected boolean handleGiveDeviceVendorId() { + assertRunOnServiceThread(); + int vendorId = mService.getVendorId(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, vendorId); @@ -112,6 +177,8 @@ abstract class HdmiCecLocalDevice { } protected boolean handleGetCecVersion(HdmiCecMessage message) { + assertRunOnServiceThread(); + int version = mService.getCecVersion(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(), message.getSource(), version); @@ -120,6 +187,8 @@ abstract class HdmiCecLocalDevice { } protected boolean handleGetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); + Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString()); mService.sendCecCommand( HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress, @@ -129,6 +198,8 @@ abstract class HdmiCecLocalDevice { } protected boolean handleGiveOsdName(HdmiCecMessage message) { + assertRunOnServiceThread(); + // Note that since this method is called after logical address allocation is done, // mDeviceInfo should not be null. HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand( @@ -149,34 +220,222 @@ abstract class HdmiCecLocalDevice { return false; } + protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { + return false; + } + + protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { + return false; + } + + protected boolean handleTerminateArc(HdmiCecMessage message) { + return false; + } + + protected boolean handleInitiateArc(HdmiCecMessage message) { + return false; + } + final void handleAddressAllocated(int logicalAddress) { + assertRunOnServiceThread(); + mAddress = mPreferredAddress = logicalAddress; onAddressAllocated(logicalAddress); } HdmiCecDeviceInfo getDeviceInfo() { + assertRunOnServiceThread(); return mDeviceInfo; } void setDeviceInfo(HdmiCecDeviceInfo info) { + assertRunOnServiceThread(); mDeviceInfo = info; } // Returns true if the logical address is same as the argument. boolean isAddressOf(int addr) { + assertRunOnServiceThread(); return addr == mAddress; } // Resets the logical address to unregistered(15), meaning the logical device is invalid. void clearAddress() { + assertRunOnServiceThread(); mAddress = HdmiCec.ADDR_UNREGISTERED; } void setPreferredAddress(int addr) { + assertRunOnServiceThread(); mPreferredAddress = addr; } int getPreferredAddress() { + assertRunOnServiceThread(); return mPreferredAddress; } + + void addAndStartAction(final FeatureAction action) { + assertRunOnServiceThread(); + mActions.add(action); + action.start(); + } + + // See if we have an action of a given type in progress. + <T extends FeatureAction> boolean hasAction(final Class<T> clazz) { + assertRunOnServiceThread(); + for (FeatureAction action : mActions) { + if (action.getClass().equals(clazz)) { + return true; + } + } + return false; + } + + // Returns all actions matched with given class type. + <T extends FeatureAction> List<T> getActions(final Class<T> clazz) { + assertRunOnServiceThread(); + ArrayList<T> actions = new ArrayList<>(); + for (FeatureAction action : mActions) { + if (action.getClass().equals(clazz)) { + actions.add((T) action); + } + } + return actions; + } + + /** + * Remove the given {@link FeatureAction} object from the action queue. + * + * @param action {@link FeatureAction} to remove + */ + void removeAction(final FeatureAction action) { + assertRunOnServiceThread(); + mActions.remove(action); + } + + // Remove all actions matched with the given Class type. + <T extends FeatureAction> void removeAction(final Class<T> clazz) { + removeActionExcept(clazz, null); + } + + // Remove all actions matched with the given Class type besides |exception|. + <T extends FeatureAction> void removeActionExcept(final Class<T> clazz, + final FeatureAction exception) { + assertRunOnServiceThread(); + Iterator<FeatureAction> iter = mActions.iterator(); + while (iter.hasNext()) { + FeatureAction action = iter.next(); + if (action != exception && action.getClass().equals(clazz)) { + action.clear(); + mActions.remove(action); + } + } + } + + protected void assertRunOnServiceThread() { + if (Looper.myLooper() != mService.getServiceLooper()) { + throw new IllegalStateException("Should run on service thread."); + } + } + + /** + * Called when a hot-plug event issued. + * + * @param portId id of port where a hot-plug event happened + * @param connected whether to connected or not on the event + */ + void onHotplug(int portId, boolean connected) { + } + + final HdmiControlService getService() { + return mService; + } + + final boolean isConnectedToArcPort(int path) { + return mService.isConnectedToArcPort(path); + } + + int getActiveSource() { + synchronized (mLock) { + return mActiveSource; + } + } + + /** + * Returns the active routing path. + */ + int getActivePath() { + synchronized (mLock) { + return mActiveRoutingPath; + } + } + + /** + * Returns the ID of the active HDMI port. The active input is the port that has the active + * routing path connected directly or indirectly under the device hierarchy. + */ + int getActiveInput() { + synchronized (mLock) { + return mService.pathToPortId(mActiveRoutingPath); + } + } + + void updateActiveDevice(int logicalAddress, int physicalAddress) { + synchronized (mLock) { + mActiveSource = logicalAddress; + mActiveRoutingPath = physicalAddress; + } + } + + void setInputChangeEnabled(boolean enabled) { + synchronized (mLock) { + mInputChangeEnabled = enabled; + } + } + + boolean isInPresetInstallationMode() { + synchronized (mLock) { + return !mInputChangeEnabled; + } + } + + /** + * Whether the given path is located in the tail of current active path. + * + * @param path to be tested + * @return true if the given path is located in the tail of current active path; otherwise, + * false + */ + // TODO: move this to local device tv. + boolean isTailOfActivePath(int path) { + synchronized (mLock) { + // If active routing path is internal source, return false. + if (mActiveRoutingPath == 0) { + return false; + } + for (int i = 12; i >= 0; i -= 4) { + int curActivePath = (mActiveRoutingPath >> i) & 0xF; + if (curActivePath == 0) { + return true; + } else { + int curPath = (path >> i) & 0xF; + if (curPath != curActivePath) { + return false; + } + } + } + return false; + } + } + + HdmiCecMessageCache getCecMessageCache() { + assertRunOnServiceThread(); + return mCecMessageCache; + } + + int pathToPortId(int newPath) { + assertRunOnServiceThread(); + return mService.pathToPortId(newPath); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index d79e283..01345ef 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -17,11 +17,15 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.IHdmiControlCallback; +import android.os.RemoteException; +import android.util.Slog; /** * Represent a logical device of type Playback residing in Android system. */ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { + private static final String TAG = "HdmiCecLocalDevicePlayback"; HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiCec.DEVICE_PLAYBACK); @@ -32,4 +36,54 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, mService.getPhysicalAddress(), mDeviceType)); } + + void oneTouchPlay(IHdmiControlCallback callback) { + assertRunOnServiceThread(); + if (hasAction(OneTouchPlayAction.class)) { + Slog.w(TAG, "oneTouchPlay already in progress"); + invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); + return; + } + + // TODO: Consider the case of multiple TV sets. For now we always direct the command + // to the primary one. + OneTouchPlayAction action = OneTouchPlayAction.create(this, HdmiCec.ADDR_TV, callback); + if (action == null) { + Slog.w(TAG, "Cannot initiate oneTouchPlay"); + invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); + return; + } + addAndStartAction(action); + } + + void queryDisplayStatus(IHdmiControlCallback callback) { + assertRunOnServiceThread(); + if (hasAction(DevicePowerStatusAction.class)) { + Slog.w(TAG, "queryDisplayStatus already in progress"); + invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); + return; + } + DevicePowerStatusAction action = DevicePowerStatusAction.create(this, + HdmiCec.ADDR_TV, callback); + if (action == null) { + Slog.w(TAG, "Cannot initiate queryDisplayStatus"); + invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); + return; + } + addAndStartAction(action); + } + + private void invokeCallback(IHdmiControlCallback callback, int result) { + try { + callback.onComplete(result); + } catch (RemoteException e) { + Slog.e(TAG, "Invoking callback failed:" + e); + } + } + + @Override + void onHotplug(int portId, boolean connected) { + // TODO: clear devices connected to the given port id. + mCecMessageCache.flushAll(); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 625b256..92ddd3d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -22,9 +22,12 @@ import android.hardware.hdmi.HdmiCecMessage; import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; +import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -35,12 +38,25 @@ import java.util.Locale; final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { private static final String TAG = "HdmiCecLocalDeviceTv"; + // Whether ARC is "enabled" or not. + @GuardedBy("mLock") + private boolean mArcStatusEnabled = false; + + @GuardedBy("mLock") + // Whether SystemAudioMode is "On" or not. + private boolean mSystemAudioMode; + + // Map-like container of all cec devices including local ones. + // A logical address of device is used as key of container. + private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>(); + HdmiCecLocalDeviceTv(HdmiControlService service) { super(service, HdmiCec.DEVICE_TV); } @Override protected void onAddressAllocated(int logicalAddress) { + assertRunOnServiceThread(); // TODO: vendor-specific initialization here. mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( @@ -59,14 +75,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param callback callback object to report the result with */ void deviceSelect(int targetAddress, IHdmiControlCallback callback) { + assertRunOnServiceThread(); HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress); if (targetDevice == null) { invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE); return; } - mService.removeAction(DeviceSelectAction.class); - mService.addAndStartAction(new DeviceSelectAction(mService, mAddress, - mService.getPhysicalAddress(), targetDevice, callback)); + removeAction(DeviceSelectAction.class); + addAndStartAction(new DeviceSelectAction(this, targetDevice, callback)); } private static void invokeCallback(IHdmiControlCallback callback, int result) { @@ -79,6 +95,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @Override protected boolean handleGetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( mAddress, Locale.getDefault().getISO3Language()); // TODO: figure out how to handle failed to get language code. @@ -92,8 +109,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @Override protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { + assertRunOnServiceThread(); // Ignore if [Device Discovery Action] is going on. - if (mService.hasAction(DeviceDiscoveryAction.class)) { + if (hasAction(DeviceDiscoveryAction.class)) { Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> " + "because Device Discovery Action is on-going:" + message); return true; @@ -104,16 +122,16 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // If it is a new device and connected to the tail of active path, // it's required to change routing path. - boolean requireRoutingChange = !mService.isInDeviceList(physicalAddress, logicalAddress) - && mService.isTailOfActivePath(physicalAddress); - mService.addAndStartAction(new NewDeviceAction(mService, - mAddress, message.getSource(), physicalAddress, + boolean requireRoutingChange = !isInDeviceList(physicalAddress, logicalAddress) + && isTailOfActivePath(physicalAddress); + addAndStartAction(new NewDeviceAction(this, message.getSource(), physicalAddress, requireRoutingChange)); return true; } @Override protected boolean handleVendorSpecificCommand(HdmiCecMessage message) { + assertRunOnServiceThread(); List<VendorSpecificAction> actions = Collections.emptyList(); // TODO: Call mService.getActions(VendorSpecificAction.class) to get all the actions. @@ -138,27 +156,304 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } private void launchDeviceDiscovery() { - mService.clearAllDeviceInfo(); - // TODO: Move the following callback to HdmiLocalDeviceTv. - DeviceDiscoveryAction action = new DeviceDiscoveryAction(mService, mAddress, + assertRunOnServiceThread(); + clearDeviceInfoList(); + DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, new DeviceDiscoveryCallback() { @Override public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { for (HdmiCecDeviceInfo info : deviceInfos) { - mService.addCecDevice(info); + addCecDevice(info); } // Since we removed all devices when it's start and // device discovery action does not poll local devices, // we should put device info of local device manually here for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { - mService.addCecDevice(device.getDeviceInfo()); + addCecDevice(device.getDeviceInfo()); } - mService.addAndStartAction(new HotplugDetectionAction(mService, - mAddress)); + addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); } }); - mService.addAndStartAction(action); + addAndStartAction(action); + } + + // Clear all device info. + private void clearDeviceInfoList() { + assertRunOnServiceThread(); + mDeviceInfos.clear(); + } + + void setSystemAudioMode(boolean on) { + synchronized (mLock) { + if (on != mSystemAudioMode) { + mSystemAudioMode = on; + // TODO: Need to set the preference for SystemAudioMode. + // TODO: Need to handle the notification of changing the mode and + // to identify the notification should be handled in the service or TvSettings. + } + } + } + + boolean getSystemAudioMode() { + synchronized (mLock) { + assertRunOnServiceThread(); + return mSystemAudioMode; + } + } + + /** + * Change ARC status into the given {@code enabled} status. + * + * @return {@code true} if ARC was in "Enabled" status + */ + boolean setArcStatus(boolean enabled) { + synchronized (mLock) { + boolean oldStatus = mArcStatusEnabled; + // 1. Enable/disable ARC circuit. + mService.setAudioReturnChannel(enabled); + + // TODO: notify arc mode change to AudioManager. + + // 2. Update arc status; + mArcStatusEnabled = enabled; + return oldStatus; + } + } + + /** + * Returns whether ARC is enabled or not. + */ + boolean getArcStatus() { + synchronized (mLock) { + return mArcStatusEnabled; + } + } + + void setAudioStatus(boolean mute, int volume) { + mService.setAudioStatus(mute, volume); + } + + @Override + protected boolean handleInitiateArc(HdmiCecMessage message) { + assertRunOnServiceThread(); + // In case where <Initiate Arc> is started by <Request ARC Initiation> + // need to clean up RequestArcInitiationAction. + removeAction(RequestArcInitiationAction.class); + SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, + message.getSource(), true); + addAndStartAction(action); + return true; + } + + @Override + protected boolean handleTerminateArc(HdmiCecMessage message) { + assertRunOnServiceThread(); + // In case where <Terminate Arc> is started by <Request ARC Termination> + // need to clean up RequestArcInitiationAction. + // TODO: check conditions of power status by calling is_connected api + // to be added soon. + removeAction(RequestArcTerminationAction.class); + SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, + message.getSource(), false); + addAndStartAction(action); + return true; + } + + @Override + protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { + assertRunOnServiceThread(); + if (!isMessageForSystemAudio(message)) { + return false; + } + SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, + message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message)); + addAndStartAction(action); + return true; + } + + @Override + protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { + assertRunOnServiceThread(); + if (!isMessageForSystemAudio(message)) { + return false; + } + setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message)); + return true; + } + + private boolean isMessageForSystemAudio(HdmiCecMessage message) { + if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM + || message.getDestination() != HdmiCec.ADDR_TV + || getAvrDeviceInfo() == null) { + Slog.w(TAG, "Skip abnormal CecMessage: " + message); + return false; + } + return true; + } + + /** + * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same + * logical address as new device info's. + * + * <p>Declared as package-private. accessed by {@link HdmiControlService} only. + * + * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added. + * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo} + * that has the same logical address as new one has. + */ + HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) { + assertRunOnServiceThread(); + HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress()); + if (oldDeviceInfo != null) { + removeDeviceInfo(deviceInfo.getLogicalAddress()); + } + mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo); + return oldDeviceInfo; + } + + /** + * Remove a device info corresponding to the given {@code logicalAddress}. + * It returns removed {@link HdmiCecDeviceInfo} if exists. + * + * <p>Declared as package-private. accessed by {@link HdmiControlService} only. + * + * @param logicalAddress logical address of device to be removed + * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null} + */ + HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) { + assertRunOnServiceThread(); + HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress); + if (deviceInfo != null) { + mDeviceInfos.remove(logicalAddress); + } + return deviceInfo; + } + + /** + * Return a list of all {@link HdmiCecDeviceInfo}. + * + * <p>Declared as package-private. accessed by {@link HdmiControlService} only. + */ + List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) { + assertRunOnServiceThread(); + if (includelLocalDevice) { + return HdmiUtils.sparseArrayToList(mDeviceInfos); + } else { + + ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>(); + for (int i = 0; i < mDeviceInfos.size(); ++i) { + HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i); + if (!isLocalDeviceAddress(info.getLogicalAddress())) { + infoList.add(info); + } + } + return infoList; + } + } + + private boolean isLocalDeviceAddress(int address) { + assertRunOnServiceThread(); + for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { + if (device.isAddressOf(address)) { + return true; + } + } + return false; + } + + /** + * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}. + * + * <p>Declared as package-private. accessed by {@link HdmiControlService} only. + * + * @param logicalAddress logical address to be retrieved + * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}. + * Returns null if no logical address matched + */ + HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { + assertRunOnServiceThread(); + return mDeviceInfos.get(logicalAddress); + } + + HdmiCecDeviceInfo getAvrDeviceInfo() { + assertRunOnServiceThread(); + return getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM); + } + + /** + * Called when a device is newly added or a new device is detected. + * + * @param info device info of a new device. + */ + final void addCecDevice(HdmiCecDeviceInfo info) { + assertRunOnServiceThread(); + addDeviceInfo(info); + + // TODO: announce new device detection. + } + + /** + * Called when a device is removed or removal of device is detected. + * + * @param address a logical address of a device to be removed + */ + final void removeCecDevice(int address) { + assertRunOnServiceThread(); + removeDeviceInfo(address); + mCecMessageCache.flushMessagesFrom(address); + + // TODO: announce a device removal. + } + + /** + * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches + * the given routing path. CEC devices use routing path for its physical address to + * describe the hierarchy of the devices in the network. + * + * @param path routing path or physical address + * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null + */ + final HdmiCecDeviceInfo getDeviceInfoByPath(int path) { + assertRunOnServiceThread(); + for (HdmiCecDeviceInfo info : getDeviceInfoList(false)) { + if (info.getPhysicalAddress() == path) { + return info; + } + } + return null; + } + + /** + * Whether a device of the specified physical address and logical address exists + * in a device info list. However, both are minimal condition and it could + * be different device from the original one. + * + * @param physicalAddress physical address of a device to be searched + * @param logicalAddress logical address of a device to be searched + * @return true if exist; otherwise false + */ + boolean isInDeviceList(int physicalAddress, int logicalAddress) { + assertRunOnServiceThread(); + HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress); + if (device == null) { + return false; + } + return device.getPhysicalAddress() == physicalAddress; + } + + @Override + void onHotplug(int portNo, boolean connected) { + assertRunOnServiceThread(); + // TODO: delegate onHotplug event to each local device. + + // Tv device will have permanent HotplugDetectionAction. + List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class); + if (!hotplugActions.isEmpty()) { + // Note that hotplug action is single action running on a machine. + // "pollAllDevicesNow" cleans up timer and start poll action immediately. + hotplugActions.get(0).pollAllDevicesNow(); + } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index eb356e9..1c53b58 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -37,14 +37,11 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; /** @@ -101,10 +98,6 @@ public final class HdmiControlService extends SystemService { // and sparse call it shares a thread to handle IO operations. private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); - // A collection of FeatureAction. - // Note that access to this collection should happen in service thread. - private final LinkedList<FeatureAction> mActions = new LinkedList<>(); - // Used to synchronize the access to the service. private final Object mLock = new Object(); @@ -130,8 +123,6 @@ public final class HdmiControlService extends SystemService { // Handler running on service thread. It's used to run a task in service thread. private final Handler mHandler = new Handler(); - private final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache(); - @Nullable private HdmiCecController mCecController; @@ -142,37 +133,10 @@ public final class HdmiControlService extends SystemService { // from being modified. private List<HdmiPortInfo> mPortInfo; - // Logical address of the active source. - @GuardedBy("mLock") - private int mActiveSource; - - // Active routing path. Physical address of the active source but not all the time, such as - // when the new active source does not claim itself to be one. Note that we don't keep - // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}. - @GuardedBy("mLock") - private int mActiveRoutingPath; - - // Set to true while the service is in normal mode. While set to false, no input change is - // allowed. Used for situations where input change can confuse users such as channel auto-scan, - // system upgrade, etc., a.k.a. "prohibit mode". - @GuardedBy("mLock") - private boolean mInputChangeEnabled; - - @GuardedBy("mLock") - // Whether ARC is "enabled" or not. - // TODO: it may need to hold lock if it's accessed from others. - private boolean mArcStatusEnabled = false; - - @GuardedBy("mLock") - // Whether SystemAudioMode is "On" or not. - private boolean mSystemAudioMode; - public HdmiControlService(Context context) { super(context); mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); - // TODO: Get control flag from persistent storage - mInputChangeEnabled = true; } @Override @@ -345,44 +309,6 @@ public final class HdmiControlService extends SystemService { return mHandler.getLooper(); } - int getActiveSource() { - synchronized (mLock) { - return mActiveSource; - } - } - - /** - * Returns the active routing path. - */ - int getActivePath() { - synchronized (mLock) { - return mActiveRoutingPath; - } - } - - /** - * Returns the ID of the active HDMI port. The active input is the port that has the active - * routing path connected directly or indirectly under the device hierarchy. - */ - int getActiveInput() { - synchronized (mLock) { - return pathToPortId(mActiveRoutingPath); - } - } - - void updateActiveDevice(int logicalAddress, int physicalAddress) { - synchronized (mLock) { - mActiveSource = logicalAddress; - mActiveRoutingPath = physicalAddress; - } - } - - void setInputChangeEnabled(boolean enabled) { - synchronized (mLock) { - mInputChangeEnabled = enabled; - } - } - /** * Returns physical address of the device. */ @@ -399,7 +325,11 @@ public final class HdmiControlService extends SystemService { HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); - return mCecController.getDeviceInfo(logicalAddress); + HdmiCecLocalDeviceTv tv = tv(); + if (tv == null) { + return null; + } + return tv.getDeviceInfo(logicalAddress); } /** @@ -410,67 +340,6 @@ public final class HdmiControlService extends SystemService { } /** - * Returns a list of {@link HdmiCecDeviceInfo}. - * - * @param includeLocalDevice whether to include local devices - */ - List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) { - assertRunOnServiceThread(); - return mCecController.getDeviceInfoList(includeLocalDevice); - } - - /** - * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches - * the given routing path. CEC devices use routing path for its physical address to - * describe the hierarchy of the devices in the network. - * - * @param path routing path or physical address - * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null - */ - HdmiCecDeviceInfo getDeviceInfoByPath(int path) { - assertRunOnServiceThread(); - for (HdmiCecDeviceInfo info : mCecController.getDeviceInfoList(false)) { - if (info.getPhysicalAddress() == path) { - return info; - } - } - return null; - } - - /** - * Add and start a new {@link FeatureAction} to the action queue. - * - * @param action {@link FeatureAction} to add and start - */ - void addAndStartAction(final FeatureAction action) { - // TODO: may need to check the number of stale actions. - runOnServiceThread(new Runnable() { - @Override - public void run() { - mActions.add(action); - action.start(); - } - }); - } - - void setSystemAudioMode(boolean on) { - synchronized (mLock) { - if (on != mSystemAudioMode) { - mSystemAudioMode = on; - // TODO: Need to set the preference for SystemAudioMode. - // TODO: Need to handle the notification of changing the mode and - // to identify the notification should be handled in the service or TvSettings. - } - } - } - - boolean getSystemAudioMode() { - synchronized (mLock) { - return mSystemAudioMode; - } - } - - /** * Whether a device of the specified physical address is connected to ARC enabled port. */ boolean isConnectedToArcPort(int physicalAddress) { @@ -483,57 +352,7 @@ public final class HdmiControlService extends SystemService { return false; } - // See if we have an action of a given type in progress. - <T extends FeatureAction> boolean hasAction(final Class<T> clazz) { - for (FeatureAction action : mActions) { - if (action.getClass().equals(clazz)) { - return true; - } - } - return false; - } - - // Returns all actions matched with given class type. - <T extends FeatureAction> List<T> getActions(final Class<T> clazz) { - ArrayList<T> actions = new ArrayList<>(); - for (FeatureAction action : mActions) { - if (action.getClass().equals(clazz)) { - actions.add((T) action); - } - } - return actions; - } - - /** - * Remove the given {@link FeatureAction} object from the action queue. - * - * @param action {@link FeatureAction} to remove - */ - void removeAction(final FeatureAction action) { - assertRunOnServiceThread(); - mActions.remove(action); - } - - // Remove all actions matched with the given Class type. - <T extends FeatureAction> void removeAction(final Class<T> clazz) { - removeActionExcept(clazz, null); - } - - // Remove all actions matched with the given Class type besides |exception|. - <T extends FeatureAction> void removeActionExcept(final Class<T> clazz, - final FeatureAction exception) { - assertRunOnServiceThread(); - Iterator<FeatureAction> iter = mActions.iterator(); - while (iter.hasNext()) { - FeatureAction action = iter.next(); - if (action != exception && action.getClass().equals(clazz)) { - action.clear(); - mActions.remove(action); - } - } - } - - private void runOnServiceThread(Runnable runnable) { + void runOnServiceThread(Runnable runnable) { mHandler.post(runnable); } @@ -548,35 +367,6 @@ public final class HdmiControlService extends SystemService { } /** - * Change ARC status into the given {@code enabled} status. - * - * @return {@code true} if ARC was in "Enabled" status - */ - boolean setArcStatus(boolean enabled) { - assertRunOnServiceThread(); - synchronized (mLock) { - boolean oldStatus = mArcStatusEnabled; - // 1. Enable/disable ARC circuit. - mCecController.setAudioReturnChannel(enabled); - - // TODO: notify arc mode change to AudioManager. - - // 2. Update arc status; - mArcStatusEnabled = enabled; - return oldStatus; - } - } - - /** - * Returns whether ARC is enabled or not. - */ - boolean getArcStatus() { - synchronized (mLock) { - return mArcStatusEnabled; - } - } - - /** * Transmit a CEC command to CEC bus. * * @param command CEC command to send out @@ -591,47 +381,17 @@ public final class HdmiControlService extends SystemService { } boolean handleCecCommand(HdmiCecMessage message) { - // Cache incoming message. Note that it caches only white-listed one. - mCecMessageCache.cacheMessage(message); - - // Commands that queries system information replies directly instead - // of creating FeatureAction because they are state-less. - // TODO: move the leftover message to local device. - switch (message.getOpcode()) { - case HdmiCec.MESSAGE_INITIATE_ARC: - handleInitiateArc(message); - return true; - case HdmiCec.MESSAGE_TERMINATE_ARC: - handleTerminateArc(message); - return true; - case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE: - handleSetSystemAudioMode(message); - return true; - case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: - handleSystemAudioModeStatus(message); - return true; - default: - if (dispatchMessageToAction(message)) { - return true; - } - break; - } - return dispatchMessageToLocalDevice(message); } - private boolean dispatchMessageToAction(HdmiCecMessage message) { - for (FeatureAction action : mActions) { - if (action.processCommand(message)) { - return true; - } - } - return false; + void setAudioReturnChannel(boolean enabled) { + mCecController.setAudioReturnChannel(enabled); } private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { - if (device.dispatchMessage(message)) { + if (device.dispatchMessage(message) + && message.getDestination() != HdmiCec.ADDR_BROADCAST) { return true; } } @@ -648,14 +408,9 @@ public final class HdmiControlService extends SystemService { */ void onHotplug(int portNo, boolean connected) { assertRunOnServiceThread(); - // TODO: delegate onHotplug event to each local device. - - // Tv device will have permanent HotplugDetectionAction. - List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class); - if (!hotplugActions.isEmpty()) { - // Note that hotplug action is single action running on a machine. - // "pollAllDevicesNow" cleans up timer and start poll action immediately. - hotplugActions.get(0).pollAllDevicesNow(); + + for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { + device.onHotplug(portNo, connected); } announceHotplugEvent(portNo, connected); @@ -686,32 +441,17 @@ public final class HdmiControlService extends SystemService { return strategy | iterationStrategy; } - void clearAllDeviceInfo() { - assertRunOnServiceThread(); - mCecController.clearDeviceInfoList(); - } - List<HdmiCecLocalDevice> getAllLocalDevices() { assertRunOnServiceThread(); return mCecController.getLocalDeviceList(); } - /** - * Whether a device of the specified physical address and logical address exists - * in a device info list. However, both are minimal condition and it could - * be different device from the original one. - * - * @param physicalAddress physical address of a device to be searched - * @param logicalAddress logical address of a device to be searched - * @return true if exist; otherwise false - */ - boolean isInDeviceList(int physicalAddress, int logicalAddress) { - assertRunOnServiceThread(); - HdmiCecDeviceInfo device = mCecController.getDeviceInfo(logicalAddress); - if (device == null) { - return false; - } - return device.getPhysicalAddress() == physicalAddress; + Object getServiceLock() { + return mLock; + } + + void setAudioStatus(boolean mute, int volume) { + // TODO: Hook up with AudioManager. } private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { @@ -721,53 +461,6 @@ public final class HdmiControlService extends SystemService { getPhysicalAddress(), deviceType, getVendorId(), displayName); } - private void handleInitiateArc(HdmiCecMessage message){ - // In case where <Initiate Arc> is started by <Request ARC Initiation> - // need to clean up RequestArcInitiationAction. - removeAction(RequestArcInitiationAction.class); - SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, - message.getDestination(), message.getSource(), true); - addAndStartAction(action); - } - - private void handleTerminateArc(HdmiCecMessage message) { - // In case where <Terminate Arc> is started by <Request ARC Termination> - // need to clean up RequestArcInitiationAction. - // TODO: check conditions of power status by calling is_connected api - // to be added soon. - removeAction(RequestArcTerminationAction.class); - SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, - message.getDestination(), message.getSource(), false); - addAndStartAction(action); - } - - private void handleSetSystemAudioMode(HdmiCecMessage message) { - if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) { - return; - } - SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, - message.getDestination(), message.getSource(), - HdmiUtils.parseCommandParamSystemAudioStatus(message)); - addAndStartAction(action); - } - - private void handleSystemAudioModeStatus(HdmiCecMessage message) { - if (!isMessageForSystemAudio(message)) { - return; - } - setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message)); - } - - private boolean isMessageForSystemAudio(HdmiCecMessage message) { - if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM - || message.getDestination() != HdmiCec.ADDR_TV - || getAvrDeviceInfo() == null) { - Slog.w(TAG, "Skip abnormal CecMessage: " + message); - return false; - } - return true; - } - // Record class that monitors the event of the caller of being killed. Used to clean up // the listener list and record list accordingly. private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { @@ -824,8 +517,7 @@ public final class HdmiControlService extends SystemService { runOnServiceThread(new Runnable() { @Override public void run() { - HdmiCecLocalDeviceTv tv = - (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); + HdmiCecLocalDeviceTv tv = tv(); if (tv == null) { Slog.w(TAG, "Local playback device not available"); invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); @@ -908,51 +600,26 @@ public final class HdmiControlService extends SystemService { } } - private void oneTouchPlay(IHdmiControlCallback callback) { - if (hasAction(OneTouchPlayAction.class)) { - Slog.w(TAG, "oneTouchPlay already in progress"); - invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); - return; - } - HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); + private void oneTouchPlay(final IHdmiControlCallback callback) { + assertRunOnServiceThread(); + HdmiCecLocalDevicePlayback source = playback(); if (source == null) { Slog.w(TAG, "Local playback device not available"); invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); return; } - // TODO: Consider the case of multiple TV sets. For now we always direct the command - // to the primary one. - OneTouchPlayAction action = OneTouchPlayAction.create(this, - source.getDeviceInfo().getLogicalAddress(), - source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback); - if (action == null) { - Slog.w(TAG, "Cannot initiate oneTouchPlay"); - invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); - return; - } - addAndStartAction(action); + source.oneTouchPlay(callback); } - private void queryDisplayStatus(IHdmiControlCallback callback) { - if (hasAction(DevicePowerStatusAction.class)) { - Slog.w(TAG, "queryDisplayStatus already in progress"); - invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); - return; - } - HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); + private void queryDisplayStatus(final IHdmiControlCallback callback) { + assertRunOnServiceThread(); + HdmiCecLocalDevicePlayback source = playback(); if (source == null) { Slog.w(TAG, "Local playback device not available"); invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); return; } - DevicePowerStatusAction action = DevicePowerStatusAction.create(this, - source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback); - if (action == null) { - Slog.w(TAG, "Cannot initiate queryDisplayStatus"); - invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); - return; - } - addAndStartAction(action); + source.queryDisplayStatus(callback); } private void addHotplugEventListener(IHdmiHotplugEventListener listener) { @@ -1003,43 +670,6 @@ public final class HdmiControlService extends SystemService { } } - HdmiCecDeviceInfo getAvrDeviceInfo() { - return mCecController.getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM); - } - - void setAudioStatus(boolean mute, int volume) { - // TODO: Hook up with AudioManager. - } - - boolean isInPresetInstallationMode() { - synchronized (mLock) { - return !mInputChangeEnabled; - } - } - - /** - * Called when a device is newly added or a new device is detected. - * - * @param info device info of a new device. - */ - void addCecDevice(HdmiCecDeviceInfo info) { - mCecController.addDeviceInfo(info); - - // TODO: announce new device detection. - } - - /** - * Called when a device is removed or removal of device is detected. - * - * @param address a logical address of a device to be removed - */ - void removeCecDevice(int address) { - mCecController.removeDeviceInfo(address); - mCecMessageCache.flushMessagesFrom(address); - - // TODO: announce a device removal. - } - private void announceHotplugEvent(int portNo, boolean connected) { HdmiHotplugEvent event = new HdmiHotplugEvent(portNo, connected); synchronized (mLock) { @@ -1058,39 +688,16 @@ public final class HdmiControlService extends SystemService { } } - HdmiCecMessageCache getCecMessageCache() { - return mCecMessageCache; - } - private static boolean hasSameTopPort(int path1, int path2) { return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); } - /** - * Whether the given path is located in the tail of current active path. - * - * @param path to be tested - * @return true if the given path is located in the tail of current active path; otherwise, - * false - */ - // TODO: move this to local device tv. - boolean isTailOfActivePath(int path) { - // If active routing path is internal source, return false. - if (mActiveRoutingPath == 0) { - return false; - } - for (int i = 12; i >= 0; i -= 4) { - int curActivePath = (mActiveRoutingPath >> i) & 0xF; - if (curActivePath == 0) { - return true; - } else { - int curPath = (path >> i) & 0xF; - if (curPath != curActivePath) { - return false; - } - } - } - return false; + private HdmiCecLocalDeviceTv tv() { + return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); + } + + private HdmiCecLocalDevicePlayback playback() { + return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index b534377..9b7cc8d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -19,6 +19,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import android.util.Slog; +import android.util.SparseArray; import java.util.ArrayList; import java.util.Collections; @@ -111,4 +112,13 @@ final class HdmiUtils { static int threeBytesToInt(byte[] data) { return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF); } + + static <T> List<T> sparseArrayToList(SparseArray<T> array) { + ArrayList<T> list = new ArrayList<>(); + for (int i = 0; i < array.size(); ++i) { + list.add(array.valueAt(i)); + } + return list; + } + } diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java index ae20eda..74f40a6 100644 --- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java +++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java @@ -52,11 +52,10 @@ final class HotplugDetectionAction extends FeatureAction { /** * Constructor * - * @param service instance of {@link HdmiControlService} - * @param sourceAddress logical address of a device that initiate this action + * @param source {@link HdmiCecLocalDevice} instance */ - HotplugDetectionAction(HdmiControlService service, int sourceAddress) { - super(service, sourceAddress); + HotplugDetectionAction(HdmiCecLocalDevice source) { + super(source); } @Override @@ -110,7 +109,7 @@ final class HotplugDetectionAction extends FeatureAction { if (mTimeoutCount == 0) { pollAllDevices(); } else { - if (mService.getSystemAudioMode()) { + if (tv().getSystemAudioMode()) { pollAudioSystem(); } } @@ -121,7 +120,7 @@ final class HotplugDetectionAction extends FeatureAction { private void pollAllDevices() { Slog.v(TAG, "Poll all devices."); - mService.pollDevices(new DevicePollingCallback() { + pollDevices(new DevicePollingCallback() { @Override public void onPollingFinished(List<Integer> ackedAddress) { checkHotplug(ackedAddress, false); @@ -133,7 +132,7 @@ final class HotplugDetectionAction extends FeatureAction { private void pollAudioSystem() { Slog.v(TAG, "Poll audio system."); - mService.pollDevices(new DevicePollingCallback() { + pollDevices(new DevicePollingCallback() { @Override public void onPollingFinished(List<Integer> ackedAddress) { checkHotplug(ackedAddress, true); @@ -143,7 +142,7 @@ final class HotplugDetectionAction extends FeatureAction { } private void checkHotplug(List<Integer> ackedAddress, boolean audioOnly) { - BitSet currentInfos = infoListToBitSet(mService.getDeviceInfoList(false), audioOnly); + BitSet currentInfos = infoListToBitSet(tv().getDeviceInfoList(false), audioOnly); BitSet polledResult = addressListToBitSet(ackedAddress); // At first, check removed devices. @@ -195,7 +194,8 @@ final class HotplugDetectionAction extends FeatureAction { private void addDevice(int addedAddress) { // Send <Give Physical Address>. - sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, addedAddress)); + sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), + addedAddress)); } private void removeDevice(int removedAddress) { @@ -206,7 +206,7 @@ final class HotplugDetectionAction extends FeatureAction { mayCancelOneTouchRecord(removedAddress); mayDisableSystemAudioAndARC(removedAddress); - mService.removeCecDevice(removedAddress); + tv().removeCecDevice(removedAddress); } private void mayChangeRoutingPath(int address) { @@ -217,7 +217,7 @@ final class HotplugDetectionAction extends FeatureAction { } private void mayCancelDeviceSelect(int address) { - List<DeviceSelectAction> actions = mService.getActions(DeviceSelectAction.class); + List<DeviceSelectAction> actions = getActions(DeviceSelectAction.class); if (actions.isEmpty()) { return; } @@ -225,7 +225,7 @@ final class HotplugDetectionAction extends FeatureAction { // Should ave only one Device Select Action DeviceSelectAction action = actions.get(0); if (action.getTargetAddress() == address) { - mService.removeAction(DeviceSelectAction.class); + removeAction(DeviceSelectAction.class); } } @@ -239,11 +239,9 @@ final class HotplugDetectionAction extends FeatureAction { } // Turn off system audio mode. - mService.setSystemAudioMode(false); - if (mService.getArcStatus()) { - mService.addAndStartAction( - new RequestArcTerminationAction(mService, mSourceAddress, address)); + tv().setSystemAudioMode(false); + if (tv().getArcStatus()) { + addAndStartAction(new RequestArcTerminationAction(localDevice(), address)); } - } } diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java index 2cae507..4a49f09 100644 --- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java +++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java @@ -56,15 +56,14 @@ final class NewDeviceAction extends FeatureAction { /** * Constructor. * - * @param service {@link HdmiControlService} instance - * @param sourceAddress logical address to be used as source address + * @param source {@link HdmiCecLocalDevice} instance * @param deviceLogicalAddress logical address of the device in interest * @param devicePhysicalAddress physical address of the device in interest * @param requireRoutingChange whether to initiate routing change or not */ - NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress, + NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress, int devicePhysicalAddress, boolean requireRoutingChange) { - super(service, sourceAddress); + super(source); mDeviceLogicalAddress = deviceLogicalAddress; mDevicePhysicalAddress = devicePhysicalAddress; mVendorId = HdmiCec.UNKNOWN_VENDOR_ID; @@ -73,16 +72,16 @@ final class NewDeviceAction extends FeatureAction { @Override public boolean start() { - if (HdmiCec.getTypeFromAddress(mSourceAddress) == HdmiCec.DEVICE_AUDIO_SYSTEM) { - if (mService.getAvrDeviceInfo() == null) { + if (HdmiCec.getTypeFromAddress(getSourceAddress()) == HdmiCec.DEVICE_AUDIO_SYSTEM) { + if (tv().getAvrDeviceInfo() == null) { // TODO: Start system audio initiation action } // If new device is connected through ARC enabled port, // initiates ARC channel establishment. - if (mService.isConnectedToArcPort(mDevicePhysicalAddress)) { - mService.addAndStartAction(new RequestArcInitiationAction(mService, mSourceAddress, - mDeviceLogicalAddress)); + if (tv().isConnectedToArcPort(mDevicePhysicalAddress)) { + addAndStartAction(new RequestArcInitiationAction(localDevice(), + mDeviceLogicalAddress)); } } @@ -95,7 +94,7 @@ final class NewDeviceAction extends FeatureAction { return true; } - sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, + sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(), mDeviceLogicalAddress)); addTimer(mState, TIMEOUT_MS); return true; @@ -155,14 +154,14 @@ final class NewDeviceAction extends FeatureAction { private void startRoutingChange() { // Stop existing routing control. - mService.removeAction(RoutingControlAction.class); + removeAction(RoutingControlAction.class); // Send routing change. The the address is a path of the active port. int newPath = toTopMostPortPath(mDevicePhysicalAddress); - sendCommand(HdmiCecMessageBuilder.buildRoutingChange(mSourceAddress, - mService.getActivePath(), newPath)); - mService.addAndStartAction(new RoutingControlAction(mService, mSourceAddress, - mService.pathToPortId(newPath), null)); + sendCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(), + localDevice().getActivePath(), newPath)); + addAndStartAction(new RoutingControlAction(localDevice(), + localDevice().pathToPortId(newPath), null)); } private static int toTopMostPortPath(int physicalAddress) { @@ -170,7 +169,7 @@ final class NewDeviceAction extends FeatureAction { } private boolean mayProcessCommandIfCached(int destAddress, int opcode) { - HdmiCecMessage message = mService.getCecMessageCache().getMessage(destAddress, opcode); + HdmiCecMessage message = getCecMessageCache().getMessage(destAddress, opcode); if (message != null) { return processCommand(message); } @@ -184,7 +183,7 @@ final class NewDeviceAction extends FeatureAction { if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) { return; } - sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, + sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(), mDeviceLogicalAddress)); addTimer(mState, TIMEOUT_MS); } @@ -193,7 +192,7 @@ final class NewDeviceAction extends FeatureAction { if (mDisplayName == null) { mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress); } - mService.addCecDevice(new HdmiCecDeviceInfo( + tv().addCecDevice(new HdmiCecDeviceInfo( mDeviceLogicalAddress, mDevicePhysicalAddress, HdmiCec.getTypeFromAddress(mDeviceLogicalAddress), mVendorId, mDisplayName)); diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index 69fad13..e0a3a8b 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -30,7 +30,7 @@ import android.util.Slog; * <p>Package-private, accessed by {@link HdmiControlService} only. */ -public final class OneTouchPlayAction extends FeatureAction { +final class OneTouchPlayAction extends FeatureAction { private static final String TAG = "OneTouchPlayAction"; // State in which the action is waiting for <Report Power Status>. In normal situation @@ -48,34 +48,32 @@ public final class OneTouchPlayAction extends FeatureAction { // We wait up to RESPONSE_TIMEOUT_MS * LOOP_COUNTER_MAX = 20 seconds. private static final int LOOP_COUNTER_MAX = 10; - private final int mSourcePath; private final int mTargetAddress; private final IHdmiControlCallback mCallback; private int mPowerStatusCounter = 0; // Factory method. Ensures arguments are valid. - static OneTouchPlayAction create(HdmiControlService service, int sourceAddress, - int sourcePath, int targetAddress, IHdmiControlCallback callback) { - if (service == null || callback == null) { + static OneTouchPlayAction create(HdmiCecLocalDevice source, + int targetAddress, IHdmiControlCallback callback) { + if (source == null || callback == null) { Slog.e(TAG, "Wrong arguments"); return null; } - return new OneTouchPlayAction(service, sourceAddress, sourcePath, targetAddress, callback); + return new OneTouchPlayAction(source, targetAddress, + callback); } - private OneTouchPlayAction(HdmiControlService service, int sourceAddress, int sourcePath, - int targetAddress, IHdmiControlCallback callback) { - super(service, sourceAddress); - mSourcePath = sourcePath; + private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress, + IHdmiControlCallback callback) { + super(localDevice); mTargetAddress = targetAddress; mCallback = callback; } @Override boolean start() { - mService.sendCecCommand( - HdmiCecMessageBuilder.buildTextViewOn(mSourceAddress, mTargetAddress)); + sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress)); broadcastActiveSource(); queryDevicePowerStatus(); mState = STATE_WAITING_FOR_REPORT_POWER_STATUS; @@ -84,13 +82,12 @@ public final class OneTouchPlayAction extends FeatureAction { } private void broadcastActiveSource() { - mService.sendCecCommand( - HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath)); + sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath())); } private void queryDevicePowerStatus() { - mService.sendCecCommand( - HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress)); + sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), + mTargetAddress)); } @Override diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java index 08ca306..a2e08f1 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java @@ -35,16 +35,14 @@ abstract class RequestArcAction extends FeatureAction { /** * @Constructor * - * @param service {@link HdmiControlService} instance - * @param sourceAddress logical address to be used as source address. It should - * TV type + * @param source {@link HdmiCecLocalDevice} instance * @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type * @throw IllegalArugmentException if device type of sourceAddress and avrAddress * is invalid */ - RequestArcAction(HdmiControlService service, int sourceAddress, int avrAddress) { - super(service, sourceAddress); - HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV); + RequestArcAction(HdmiCecLocalDevice source, int avrAddress) { + super(source); + HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV); HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM); mAvrAddress = avrAddress; } @@ -72,9 +70,9 @@ abstract class RequestArcAction extends FeatureAction { protected final void disableArcTransmission() { // Start Set ARC Transmission State action. - SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(mService, - mSourceAddress, mAvrAddress, false); - mService.addAndStartAction(action); + SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(localDevice(), + mAvrAddress, false); + addAndStartAction(action); } @Override diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index 343aff7..98ec953 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -31,14 +31,14 @@ final class RequestArcInitiationAction extends RequestArcAction { * * For more details look at {@link RequestArcAction#RequestArcAction}. */ - RequestArcInitiationAction(HdmiControlService service, int sourceAddress, int avrAddress) { - super(service, sourceAddress, avrAddress); + RequestArcInitiationAction(HdmiCecLocalDevice source, int avrAddress) { + super(source, avrAddress); } @Override boolean start() { - HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress, - mAvrAddress); + HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation( + getSourceAddress(), mAvrAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java index d4a35f8..19fa22b 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java @@ -31,14 +31,14 @@ final class RequestArcTerminationAction extends RequestArcAction { * * @see RequestArcAction#RequestArcAction */ - RequestArcTerminationAction(HdmiControlService service, int sourceAddress, int avrAddress) { - super(service, sourceAddress, avrAddress); + RequestArcTerminationAction(HdmiCecLocalDevice source, int avrAddress) { + super(source, avrAddress); } @Override boolean start() { HdmiCecMessage command = - HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress); + HdmiCecMessageBuilder.buildRequestArcTermination(getSourceAddress(), mAvrAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java index 19974ea..2eec846 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -39,7 +39,7 @@ import com.android.server.hdmi.HdmiControlService.SendMessageCallback; * <li> Routing at CEC enable time * </ul> */ -public class RoutingControlAction extends FeatureAction { +final class RoutingControlAction extends FeatureAction { private static final String TAG = "RoutingControlAction"; // State in which we wait for <Routing Information> to arrive. If timed out, we use the @@ -63,9 +63,8 @@ public class RoutingControlAction extends FeatureAction { // The latest routing path. Updated by each <Routing Information> from CEC switches. private int mCurrentRoutingPath; - RoutingControlAction(HdmiControlService service, int sourceAddress, int path, - IHdmiControlCallback callback) { - super(service, sourceAddress); + RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) { + super(localDevice); mCallback = callback; mCurrentRoutingPath = path; } @@ -92,7 +91,7 @@ public class RoutingControlAction extends FeatureAction { } mCurrentRoutingPath = routingPath; // Stop possible previous routing change sequence if in progress. - mService.removeAction(RoutingControlAction.class); + removeAction(RoutingControlAction.class); addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS); return true; } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS @@ -130,7 +129,8 @@ public class RoutingControlAction extends FeatureAction { } private void sendSetStreamPath() { - sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(mSourceAddress, mCurrentRoutingPath)); + sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(), + mCurrentRoutingPath)); } private static boolean isInActiveRoutingPath(int activePath, int newPath) { @@ -164,9 +164,9 @@ public class RoutingControlAction extends FeatureAction { } switch (timeoutState) { case STATE_WAIT_FOR_ROUTING_INFORMATION: - HdmiCecDeviceInfo device = mService.getDeviceInfoByPath(mCurrentRoutingPath); + HdmiCecDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath); if (device == null) { - maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath)); + maybeChangeActiveInput(tv().pathToPortId(mCurrentRoutingPath)); } else { // TODO: Also check followings and then proceed: // if routing change was neither triggered by TV at CEC enable time, nor @@ -184,7 +184,7 @@ public class RoutingControlAction extends FeatureAction { case STATE_WAIT_FOR_REPORT_POWER_STATUS: int tvPowerStatus = getTvPowerStatus(); if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) { - if (!maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath))) { + if (!maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath))) { sendSetStreamPath(); } } @@ -196,7 +196,7 @@ public class RoutingControlAction extends FeatureAction { // Called whenever an HDMI input of the TV shall become the active input. private boolean maybeChangeActiveInput(int path) { - if (mService.getActiveInput() == mService.pathToPortId(path)) { + if (localDevice().getActiveInput() == localDevice().pathToPortId(path)) { return false; } // TODO: Remember the currently active input @@ -207,7 +207,7 @@ public class RoutingControlAction extends FeatureAction { } private void queryDevicePowerStatus(int address, SendMessageCallback callback) { - sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, address), + sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address), callback); } @@ -216,7 +216,7 @@ public class RoutingControlAction extends FeatureAction { mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS); } else { - maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath)); + maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath)); } } diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java index 8e6998f..ddcda92 100644 --- a/services/core/java/com/android/server/hdmi/SendKeyAction.java +++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java @@ -16,10 +16,8 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCecMessage; -import android.view.KeyEvent; import android.util.Slog; - -import libcore.util.EmptyArray; +import android.view.KeyEvent; /** * Feature action that transmits remote control key command (User Control Press/ @@ -56,13 +54,12 @@ final class SendKeyAction extends FeatureAction { /** * Constructor. * - * @param service {@link HdmiControlService} instance - * @param sourceAddress logical address to be used as source address + * @param source {@link HdmiCecLocalDevice} instance * @param targetAddress logical address of the device to send the keys to * @param keyCode remote control key code as defined in {@link KeyEvent} */ - SendKeyAction(HdmiControlService service, int sourceAddress, int targetAddress, int keyCode) { - super(service, sourceAddress); + SendKeyAction(HdmiCecLocalDevice source, int targetAddress, int keyCode) { + super(source); mTargetAddress = targetAddress; mLastKeyCode = keyCode; } @@ -112,12 +109,13 @@ final class SendKeyAction extends FeatureAction { if (keyCodeAndParam == null) { return; } - sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(mSourceAddress, mTargetAddress, - keyCodeAndParam)); + sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), + mTargetAddress, keyCodeAndParam)); } private void sendKeyUp() { - sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(mSourceAddress, mTargetAddress)); + sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(), + mTargetAddress)); } @Override diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index d53d88d..da841c6 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -39,14 +39,13 @@ final class SetArcTransmissionStateAction extends FeatureAction { /** * @Constructor * - * @param service an instance of {@link HdmiControlService} - * @param sourceAddress logical address to be used as source address + * @param source {@link HdmiCecLocalDevice} instance * @param enabled whether to enable ARC Transmission channel */ - SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress, + SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress, boolean enabled) { - super(service, sourceAddress); - HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV); + super(source); + HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV); HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM); mAvrAddress = avrAddress; mEnabled = enabled; @@ -65,7 +64,7 @@ final class SetArcTransmissionStateAction extends FeatureAction { private void sendReportArcInitiated() { HdmiCecMessage command = - HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress); + HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { @@ -93,14 +92,14 @@ final class SetArcTransmissionStateAction extends FeatureAction { } private void setArcStatus(boolean enabled) { - boolean wasEnabled = mService.setArcStatus(enabled); + boolean wasEnabled = tv().setArcStatus(enabled); Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled); // If enabled before and set to "disabled" and send <Report Arc Terminated> to // av reciever. if (!enabled && wasEnabled) { - sendCommand( - HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress)); + sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(), + mAvrAddress)); } } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index dde3342..cf7ff90 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -47,23 +47,22 @@ abstract class SystemAudioAction extends FeatureAction { /** * Constructor * - * @param service {@link HdmiControlService} instance - * @param sourceAddress logical address of source device (TV or STB). + * @param source {@link HdmiCecLocalDevice} instance * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid */ - SystemAudioAction(HdmiControlService service, int sourceAddress, int avrAddress, - boolean targetStatus) { - super(service, sourceAddress); + SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) { + super(source); HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM); mAvrLogicalAddress = avrAddress; mTargetAudioStatus = targetStatus; } protected void sendSystemAudioModeRequest() { - int avrPhysicalAddress = mService.getAvrDeviceInfo().getPhysicalAddress(); - HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(mSourceAddress, + int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress(); + HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest( + getSourceAddress(), mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override @@ -90,11 +89,11 @@ abstract class SystemAudioAction extends FeatureAction { } protected void setSystemAudioMode(boolean mode) { - mService.setSystemAudioMode(mode); + tv().setSystemAudioMode(mode); } protected void sendGiveAudioStatus() { - HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(mSourceAddress, + HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(), mAvrLogicalAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override @@ -112,7 +111,7 @@ abstract class SystemAudioAction extends FeatureAction { private void handleSendGiveAudioStatusFailure() { // TODO: Notify the failure status. - int uiCommand = mService.getSystemAudioMode() + int uiCommand = tv().getSystemAudioMode() ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION // SystemAudioMode: ON : HdmiConstants.UI_COMMAND_MUTE_FUNCTION; // SystemAudioMode: OFF sendUserControlPressedAndReleased(uiCommand); @@ -121,9 +120,9 @@ abstract class SystemAudioAction extends FeatureAction { private void sendUserControlPressedAndReleased(int uiCommand) { sendCommand(HdmiCecMessageBuilder.buildUserControlPressed( - mSourceAddress, mAvrLogicalAddress, uiCommand)); + getSourceAddress(), mAvrLogicalAddress, uiCommand)); sendCommand(HdmiCecMessageBuilder.buildUserControlReleased( - mSourceAddress, mAvrLogicalAddress)); + getSourceAddress(), mAvrLogicalAddress)); } @Override @@ -158,7 +157,7 @@ abstract class SystemAudioAction extends FeatureAction { if (params.length > 0) { boolean mute = (params[0] & 0x80) == 0x80; int volume = params[0] & 0x7F; - mService.setAudioStatus(mute, volume); + tv().setAudioStatus(mute, volume); if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) { // Toggle AVR's mute status to match with the system audio status. sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE); @@ -171,8 +170,8 @@ abstract class SystemAudioAction extends FeatureAction { } protected void removeSystemAudioActionInProgress() { - mService.removeActionExcept(SystemAudioActionFromTv.class, this); - mService.removeActionExcept(SystemAudioActionFromAvr.class, this); + removeActionExcept(SystemAudioActionFromTv.class, this); + removeActionExcept(SystemAudioActionFromAvr.class, this); } @Override diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java index c5eb44b..3907b71 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java @@ -25,16 +25,15 @@ final class SystemAudioActionFromAvr extends SystemAudioAction { /** * Constructor * - * @param service {@link HdmiControlService} instance - * @param tvAddress logical address of TV device + * @param source {@link HdmiCecLocalDevice} instance * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid */ - SystemAudioActionFromAvr(HdmiControlService service, int tvAddress, int avrAddress, + SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) { - super(service, tvAddress, avrAddress, targetStatus); - HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV); + super(source, avrAddress, targetStatus); + HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV); } @Override @@ -45,13 +44,13 @@ final class SystemAudioActionFromAvr extends SystemAudioAction { } private void handleSystemAudioActionFromAvr() { - if (mTargetAudioStatus == mService.getSystemAudioMode()) { + if (mTargetAudioStatus == tv().getSystemAudioMode()) { finish(); return; } - if (mService.isInPresetInstallationMode()) { + if (tv().isInPresetInstallationMode()) { sendCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand( - mSourceAddress, mAvrLogicalAddress, + getSourceAddress(), mAvrLogicalAddress, HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE, HdmiConstants.ABORT_REFUSED)); mTargetAudioStatus = false; sendSystemAudioModeRequest(); diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java index 9994de6..e0c4ff4 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java @@ -26,16 +26,15 @@ final class SystemAudioActionFromTv extends SystemAudioAction { /** * Constructor * - * @param service {@link HdmiControlService} instance - * @param tvAddress logical address of TV device + * @param sourceAddress {@link HdmiCecLocalDevice} instance * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @throw IllegalArugmentException if device type of tvAddress is invalid */ - SystemAudioActionFromTv(HdmiControlService service, int tvAddress, int avrAddress, + SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress, boolean targetStatus) { - super(service, tvAddress, avrAddress, targetStatus); - HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV); + super(sourceAddress, avrAddress, targetStatus); + HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV); } @Override diff --git a/services/core/java/com/android/server/hdmi/VendorSpecificAction.java b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java index 9d45702..c954b50 100644 --- a/services/core/java/com/android/server/hdmi/VendorSpecificAction.java +++ b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java @@ -12,8 +12,8 @@ public class VendorSpecificAction extends FeatureAction { private static final int STATE_1 = 1; private static final int STATE_2 = 2; - VendorSpecificAction(HdmiControlService service, int sourceAddress) { - super(service, sourceAddress); + VendorSpecificAction(HdmiCecLocalDevice source) { + super(source); // Modify the constructor if additional arguments are necessary. } |
