Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +20 −0 Original line number Diff line number Diff line Loading @@ -617,6 +617,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); // If there is AVR, initiate System Audio Auto initiation action, // which turns on and off system audio according to last system Loading Loading @@ -1300,6 +1301,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). removeAction(DeviceDiscoveryAction.class); removeAction(HotplugDetectionAction.class); removeAction(PowerStatusMonitorAction.class); // Remove recording actions. removeAction(OneTouchRecordAction.class); removeAction(TimerRecordingAction.class); Loading Loading @@ -1521,4 +1523,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } }); } void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) { HdmiDeviceInfo info = getDeviceInfo(logicalAddress); if (info == null) { Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress); return; } if (info.getDevicePowerStatus() == newPowerStatus) { return; } HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus); // addDeviceInfo replaces old device info with new one if exists. addDeviceInfo(newInfo); // TODO: notify this update to others. } } services/core/java/com/android/server/hdmi/HdmiControlService.java +5 −2 Original line number Diff line number Diff line Loading @@ -317,7 +317,10 @@ public final class HdmiControlService extends SystemService { if (logicalAddress == Constants.ADDR_UNREGISTERED) { Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); } else { HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); // Set POWER_STATUS_ON to all local devices because they share lifetime // with system. HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, HdmiControlManager.POWER_STATUS_ON); localDevice.setDeviceInfo(deviceInfo); mCecController.addLocalDevice(deviceType, localDevice); mCecController.addLogicalAddress(logicalAddress); Loading Loading @@ -653,7 +656,7 @@ public final class HdmiControlService extends SystemService { } } private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { // TODO: find better name instead of model name. String displayName = Build.MODEL; return new HdmiDeviceInfo(logicalAddress, Loading services/core/java/com/android/server/hdmi/HdmiUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -266,4 +266,14 @@ final class HdmiUtils { } return true; } /** * Clone {@link HdmiDeviceInfo} with new power status. */ static HdmiDeviceInfo cloneHdmiDeviceInfo(HdmiDeviceInfo info, int newPowerStatus) { return new HdmiDeviceInfo(info.getLogicalAddress(), info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(), info.getVendorId(), info.getDisplayName(), newPowerStatus); } } services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java 0 → 100644 +146 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.hdmi; import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN; import android.hardware.hdmi.HdmiDeviceInfo; import android.util.SparseIntArray; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; import java.util.List; /** * Action that check each device's power status. */ public class PowerStatusMonitorAction extends HdmiCecFeatureAction { private static final String TAG = "PowerStatusMonitorAction"; // State that waits for <Report Power Status> once sending <Give Device Power Status> // to all external devices. private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1; // State that waits for next monitoring private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2; private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1; // Monitoring interval (60s) private static final int MONITIROING_INTERNAL_MS = 60000; // Timeout once sending <Give Device Power Status> private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000; // Container for current power status of all external devices. // The key is a logical address a device and the value is current power status of it // Whenever the action receives <Report Power Status> from a device, // it removes an entry of the given device. // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens, // updates power status of all remaining devices into POWER_STATUS_UNKNOWN. private final SparseIntArray mPowerStatus = new SparseIntArray(); PowerStatusMonitorAction(HdmiCecLocalDevice source) { super(source); } @Override boolean start() { queryPowerStatus(); return true; } @Override boolean processCommand(HdmiCecMessage cmd) { if (mState != STATE_WAIT_FOR_REPORT_POWER_STATUS) { return false; } return handleReportPowerStatus(cmd); } private boolean handleReportPowerStatus(HdmiCecMessage cmd) { int sourceAddress = cmd.getSource(); int oldStatus = mPowerStatus.get(sourceAddress, INVALID_POWER_STATUS); if (oldStatus == INVALID_POWER_STATUS) { // if no device exists for incoming message, hands it over to other actions. return false; } int newStatus = cmd.getParams()[0]; updatePowerStatus(sourceAddress, newStatus, true); return true; } @Override void handleTimerEvent(int state) { switch (mState) { case STATE_WAIT_FOR_NEXT_MONITORING: queryPowerStatus(); break; case STATE_WAIT_FOR_REPORT_POWER_STATUS: handleTimeout(); break; } } private void handleTimeout() { for (int i = 0; i < mPowerStatus.size(); ++i) { int logicalAddress = mPowerStatus.keyAt(i); updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, false); } mPowerStatus.clear(); mState = STATE_WAIT_FOR_NEXT_MONITORING; } private void resetPowerStatus(List<HdmiDeviceInfo> deviceInfos) { mPowerStatus.clear(); for (HdmiDeviceInfo info : deviceInfos) { mPowerStatus.append(info.getLogicalAddress(), info.getDevicePowerStatus()); } } private void queryPowerStatus() { List<HdmiDeviceInfo> deviceInfos = tv().getDeviceInfoList(false); resetPowerStatus(deviceInfos); for (HdmiDeviceInfo info : deviceInfos) { final int logicalAddress = info.getLogicalAddress(); sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), logicalAddress), new SendMessageCallback() { @Override public void onSendCompleted(int error) { // If fails to send <Give Device Power Status>, // update power status into UNKNOWN. if (error != Constants.SEND_RESULT_SUCCESS) { updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true); } } }); } mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; // Add both timers, monitoring and timeout. addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITIROING_INTERNAL_MS); addTimer(STATE_WAIT_FOR_REPORT_POWER_STATUS, REPORT_POWER_STATUS_TIMEOUT_MS); } private void updatePowerStatus(int logicalAddress, int newStatus, boolean remove) { tv().updateDevicePowerStatus(logicalAddress, newStatus); if (remove) { mPowerStatus.delete(logicalAddress); } } } Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +20 −0 Original line number Diff line number Diff line Loading @@ -617,6 +617,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); // If there is AVR, initiate System Audio Auto initiation action, // which turns on and off system audio according to last system Loading Loading @@ -1300,6 +1301,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). removeAction(DeviceDiscoveryAction.class); removeAction(HotplugDetectionAction.class); removeAction(PowerStatusMonitorAction.class); // Remove recording actions. removeAction(OneTouchRecordAction.class); removeAction(TimerRecordingAction.class); Loading Loading @@ -1521,4 +1523,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } }); } void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) { HdmiDeviceInfo info = getDeviceInfo(logicalAddress); if (info == null) { Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress); return; } if (info.getDevicePowerStatus() == newPowerStatus) { return; } HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus); // addDeviceInfo replaces old device info with new one if exists. addDeviceInfo(newInfo); // TODO: notify this update to others. } }
services/core/java/com/android/server/hdmi/HdmiControlService.java +5 −2 Original line number Diff line number Diff line Loading @@ -317,7 +317,10 @@ public final class HdmiControlService extends SystemService { if (logicalAddress == Constants.ADDR_UNREGISTERED) { Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); } else { HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); // Set POWER_STATUS_ON to all local devices because they share lifetime // with system. HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, HdmiControlManager.POWER_STATUS_ON); localDevice.setDeviceInfo(deviceInfo); mCecController.addLocalDevice(deviceType, localDevice); mCecController.addLogicalAddress(logicalAddress); Loading Loading @@ -653,7 +656,7 @@ public final class HdmiControlService extends SystemService { } } private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { // TODO: find better name instead of model name. String displayName = Build.MODEL; return new HdmiDeviceInfo(logicalAddress, Loading
services/core/java/com/android/server/hdmi/HdmiUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -266,4 +266,14 @@ final class HdmiUtils { } return true; } /** * Clone {@link HdmiDeviceInfo} with new power status. */ static HdmiDeviceInfo cloneHdmiDeviceInfo(HdmiDeviceInfo info, int newPowerStatus) { return new HdmiDeviceInfo(info.getLogicalAddress(), info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(), info.getVendorId(), info.getDisplayName(), newPowerStatus); } }
services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java 0 → 100644 +146 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.hdmi; import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN; import android.hardware.hdmi.HdmiDeviceInfo; import android.util.SparseIntArray; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; import java.util.List; /** * Action that check each device's power status. */ public class PowerStatusMonitorAction extends HdmiCecFeatureAction { private static final String TAG = "PowerStatusMonitorAction"; // State that waits for <Report Power Status> once sending <Give Device Power Status> // to all external devices. private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1; // State that waits for next monitoring private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2; private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1; // Monitoring interval (60s) private static final int MONITIROING_INTERNAL_MS = 60000; // Timeout once sending <Give Device Power Status> private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000; // Container for current power status of all external devices. // The key is a logical address a device and the value is current power status of it // Whenever the action receives <Report Power Status> from a device, // it removes an entry of the given device. // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens, // updates power status of all remaining devices into POWER_STATUS_UNKNOWN. private final SparseIntArray mPowerStatus = new SparseIntArray(); PowerStatusMonitorAction(HdmiCecLocalDevice source) { super(source); } @Override boolean start() { queryPowerStatus(); return true; } @Override boolean processCommand(HdmiCecMessage cmd) { if (mState != STATE_WAIT_FOR_REPORT_POWER_STATUS) { return false; } return handleReportPowerStatus(cmd); } private boolean handleReportPowerStatus(HdmiCecMessage cmd) { int sourceAddress = cmd.getSource(); int oldStatus = mPowerStatus.get(sourceAddress, INVALID_POWER_STATUS); if (oldStatus == INVALID_POWER_STATUS) { // if no device exists for incoming message, hands it over to other actions. return false; } int newStatus = cmd.getParams()[0]; updatePowerStatus(sourceAddress, newStatus, true); return true; } @Override void handleTimerEvent(int state) { switch (mState) { case STATE_WAIT_FOR_NEXT_MONITORING: queryPowerStatus(); break; case STATE_WAIT_FOR_REPORT_POWER_STATUS: handleTimeout(); break; } } private void handleTimeout() { for (int i = 0; i < mPowerStatus.size(); ++i) { int logicalAddress = mPowerStatus.keyAt(i); updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, false); } mPowerStatus.clear(); mState = STATE_WAIT_FOR_NEXT_MONITORING; } private void resetPowerStatus(List<HdmiDeviceInfo> deviceInfos) { mPowerStatus.clear(); for (HdmiDeviceInfo info : deviceInfos) { mPowerStatus.append(info.getLogicalAddress(), info.getDevicePowerStatus()); } } private void queryPowerStatus() { List<HdmiDeviceInfo> deviceInfos = tv().getDeviceInfoList(false); resetPowerStatus(deviceInfos); for (HdmiDeviceInfo info : deviceInfos) { final int logicalAddress = info.getLogicalAddress(); sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), logicalAddress), new SendMessageCallback() { @Override public void onSendCompleted(int error) { // If fails to send <Give Device Power Status>, // update power status into UNKNOWN. if (error != Constants.SEND_RESULT_SUCCESS) { updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true); } } }); } mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; // Add both timers, monitoring and timeout. addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITIROING_INTERNAL_MS); addTimer(STATE_WAIT_FOR_REPORT_POWER_STATUS, REPORT_POWER_STATUS_TIMEOUT_MS); } private void updatePowerStatus(int logicalAddress, int newStatus, boolean remove) { tv().updateDevicePowerStatus(logicalAddress, newStatus); if (remove) { mPowerStatus.delete(logicalAddress); } } }