PowerStatusMonitorAction.java revision 4480efa05aa5dd44f1432c3260be263546daf838
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.server.hdmi; 17 18import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN; 19 20import android.hardware.hdmi.HdmiDeviceInfo; 21import android.util.SparseIntArray; 22 23import com.android.server.hdmi.HdmiControlService.SendMessageCallback; 24 25import java.util.List; 26 27/** 28 * Action that check each device's power status. 29 */ 30public class PowerStatusMonitorAction extends HdmiCecFeatureAction { 31 private static final String TAG = "PowerStatusMonitorAction"; 32 33 // State that waits for <Report Power Status> once sending <Give Device Power Status> 34 // to all external devices. 35 private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1; 36 // State that waits for next monitoring 37 private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2; 38 39 private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1; 40 41 // Monitoring interval (60s) 42 private static final int MONITIROING_INTERNAL_MS = 60000; 43 44 // Timeout once sending <Give Device Power Status> 45 private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000; 46 47 // Container for current power status of all external devices. 48 // The key is a logical address a device and the value is current power status of it 49 // Whenever the action receives <Report Power Status> from a device, 50 // it removes an entry of the given device. 51 // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens, 52 // updates power status of all remaining devices into POWER_STATUS_UNKNOWN. 53 private final SparseIntArray mPowerStatus = new SparseIntArray(); 54 55 PowerStatusMonitorAction(HdmiCecLocalDevice source) { 56 super(source); 57 } 58 59 @Override 60 boolean start() { 61 queryPowerStatus(); 62 return true; 63 } 64 65 @Override 66 boolean processCommand(HdmiCecMessage cmd) { 67 if (mState != STATE_WAIT_FOR_REPORT_POWER_STATUS) { 68 return false; 69 } 70 return handleReportPowerStatus(cmd); 71 } 72 73 private boolean handleReportPowerStatus(HdmiCecMessage cmd) { 74 int sourceAddress = cmd.getSource(); 75 int oldStatus = mPowerStatus.get(sourceAddress, INVALID_POWER_STATUS); 76 if (oldStatus == INVALID_POWER_STATUS) { 77 // if no device exists for incoming message, hands it over to other actions. 78 return false; 79 } 80 int newStatus = cmd.getParams()[0] & 0xFF; 81 updatePowerStatus(sourceAddress, newStatus, true); 82 return true; 83 } 84 85 @Override 86 void handleTimerEvent(int state) { 87 switch (mState) { 88 case STATE_WAIT_FOR_NEXT_MONITORING: 89 queryPowerStatus(); 90 break; 91 case STATE_WAIT_FOR_REPORT_POWER_STATUS: 92 handleTimeout(); 93 break; 94 } 95 } 96 97 private void handleTimeout() { 98 for (int i = 0; i < mPowerStatus.size(); ++i) { 99 int logicalAddress = mPowerStatus.keyAt(i); 100 updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, false); 101 } 102 mPowerStatus.clear(); 103 mState = STATE_WAIT_FOR_NEXT_MONITORING; 104 } 105 106 private void resetPowerStatus(List<HdmiDeviceInfo> deviceInfos) { 107 mPowerStatus.clear(); 108 for (HdmiDeviceInfo info : deviceInfos) { 109 mPowerStatus.append(info.getLogicalAddress(), info.getDevicePowerStatus()); 110 } 111 } 112 113 private void queryPowerStatus() { 114 List<HdmiDeviceInfo> deviceInfos = tv().getDeviceInfoList(false); 115 resetPowerStatus(deviceInfos); 116 for (HdmiDeviceInfo info : deviceInfos) { 117 final int logicalAddress = info.getLogicalAddress(); 118 sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), 119 logicalAddress), 120 new SendMessageCallback() { 121 @Override 122 public void onSendCompleted(int error) { 123 // If fails to send <Give Device Power Status>, 124 // update power status into UNKNOWN. 125 if (error != Constants.SEND_RESULT_SUCCESS) { 126 updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true); 127 } 128 } 129 }); 130 } 131 132 mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; 133 134 // Add both timers, monitoring and timeout. 135 addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITIROING_INTERNAL_MS); 136 addTimer(STATE_WAIT_FOR_REPORT_POWER_STATUS, REPORT_POWER_STATUS_TIMEOUT_MS); 137 } 138 139 private void updatePowerStatus(int logicalAddress, int newStatus, boolean remove) { 140 tv().updateDevicePowerStatus(logicalAddress, newStatus); 141 142 if (remove) { 143 mPowerStatus.delete(logicalAddress); 144 } 145 } 146} 147