1410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang/* 2410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * Copyright (C) 2014 The Android Open Source Project 3410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * 4410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 5410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * you may not use this file except in compliance with the License. 6410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * You may obtain a copy of the License at 7410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * 8410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 9410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * 10410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * Unless required by applicable law or agreed to in writing, software 11410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 12410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * See the License for the specific language governing permissions and 14410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * limitations under the License. 15410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang */ 16410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangpackage com.android.server.hdmi; 17410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 18410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN; 19410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 20410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 21410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangimport android.util.SparseIntArray; 22410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 23410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangimport com.android.server.hdmi.HdmiControlService.SendMessageCallback; 24410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 25410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangimport java.util.List; 26410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 27410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang/** 28410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang * Action that check each device's power status. 29410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang */ 30410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jangpublic class PowerStatusMonitorAction extends HdmiCecFeatureAction { 31410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final String TAG = "PowerStatusMonitorAction"; 32410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 33410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // State that waits for <Report Power Status> once sending <Give Device Power Status> 34410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // to all external devices. 35410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1; 36410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // State that waits for next monitoring 37410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2; 38410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 39410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1; 40410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 41410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Monitoring interval (60s) 42410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final int MONITIROING_INTERNAL_MS = 60000; 43410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 44410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Timeout once sending <Give Device Power Status> 45410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000; 46410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 47410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Container for current power status of all external devices. 48410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // The key is a logical address a device and the value is current power status of it 49410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Whenever the action receives <Report Power Status> from a device, 50410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // it removes an entry of the given device. 51410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens, 52410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // updates power status of all remaining devices into POWER_STATUS_UNKNOWN. 53410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private final SparseIntArray mPowerStatus = new SparseIntArray(); 54410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 55410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang PowerStatusMonitorAction(HdmiCecLocalDevice source) { 56410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang super(source); 57410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 58410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 59410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang @Override 60410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang boolean start() { 61410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang queryPowerStatus(); 62410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return true; 63410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 64410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 65410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang @Override 66410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang boolean processCommand(HdmiCecMessage cmd) { 673f6755f58722bbae532171c384a294e530864ae1Jinsuk Kim if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS 683f6755f58722bbae532171c384a294e530864ae1Jinsuk Kim && cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) { 693f6755f58722bbae532171c384a294e530864ae1Jinsuk Kim return handleReportPowerStatus(cmd); 70410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 713f6755f58722bbae532171c384a294e530864ae1Jinsuk Kim return false; 72410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 73410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 74410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private boolean handleReportPowerStatus(HdmiCecMessage cmd) { 75410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang int sourceAddress = cmd.getSource(); 76410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang int oldStatus = mPowerStatus.get(sourceAddress, INVALID_POWER_STATUS); 77410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (oldStatus == INVALID_POWER_STATUS) { 78410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // if no device exists for incoming message, hands it over to other actions. 79410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return false; 80410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 814480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int newStatus = cmd.getParams()[0] & 0xFF; 82410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang updatePowerStatus(sourceAddress, newStatus, true); 83410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return true; 84410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 85410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 86410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang @Override 87410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang void handleTimerEvent(int state) { 88410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang switch (mState) { 89410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang case STATE_WAIT_FOR_NEXT_MONITORING: 90410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang queryPowerStatus(); 91410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang break; 92410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang case STATE_WAIT_FOR_REPORT_POWER_STATUS: 93410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang handleTimeout(); 94410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang break; 95410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 96410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 97410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 98410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private void handleTimeout() { 99410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang for (int i = 0; i < mPowerStatus.size(); ++i) { 100410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang int logicalAddress = mPowerStatus.keyAt(i); 101410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, false); 102410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 103410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mPowerStatus.clear(); 104410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mState = STATE_WAIT_FOR_NEXT_MONITORING; 105410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 106410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 107410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private void resetPowerStatus(List<HdmiDeviceInfo> deviceInfos) { 108410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mPowerStatus.clear(); 109410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang for (HdmiDeviceInfo info : deviceInfos) { 110410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mPowerStatus.append(info.getLogicalAddress(), info.getDevicePowerStatus()); 111410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 112410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 113410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 114410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private void queryPowerStatus() { 115410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang List<HdmiDeviceInfo> deviceInfos = tv().getDeviceInfoList(false); 116410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang resetPowerStatus(deviceInfos); 117410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang for (HdmiDeviceInfo info : deviceInfos) { 118410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang final int logicalAddress = info.getLogicalAddress(); 119410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), 120410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang logicalAddress), 121410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang new SendMessageCallback() { 122410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang @Override 123410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang public void onSendCompleted(int error) { 124410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // If fails to send <Give Device Power Status>, 125410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // update power status into UNKNOWN. 126410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (error != Constants.SEND_RESULT_SUCCESS) { 127410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true); 128410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 129410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 130410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang }); 131410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 132410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 133410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; 134410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 135410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Add both timers, monitoring and timeout. 136410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITIROING_INTERNAL_MS); 137410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addTimer(STATE_WAIT_FOR_REPORT_POWER_STATUS, REPORT_POWER_STATUS_TIMEOUT_MS); 138410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 139410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 140410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private void updatePowerStatus(int logicalAddress, int newStatus, boolean remove) { 141410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang tv().updateDevicePowerStatus(logicalAddress, newStatus); 142410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 143410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (remove) { 144410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang mPowerStatus.delete(logicalAddress); 145410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 146410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 147410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang} 148