blob: a62d0b63221cea93e5e669d7ac7481014f0bda89 [file] [log] [blame]
Jungshik Jang410ca9c2014-08-07 18:04:14 +09001/*
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;
Donghyun Chobc6e3722016-11-04 05:25:52 +090021import android.hardware.tv.cec.V1_0.SendMessageResult;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090022import android.util.SparseIntArray;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090023import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090024import java.util.List;
25
26/**
27 * Action that check each device's power status.
28 */
29public class PowerStatusMonitorAction extends HdmiCecFeatureAction {
30 private static final String TAG = "PowerStatusMonitorAction";
31
32 // State that waits for <Report Power Status> once sending <Give Device Power Status>
33 // to all external devices.
34 private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
35 // State that waits for next monitoring
36 private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2;
37
38 private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1;
39
40 // Monitoring interval (60s)
Shubanga3f59502018-06-05 16:32:53 -070041 private static final int MONITORING_INTERNAL_MS = 60000;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090042
43 // Timeout once sending <Give Device Power Status>
44 private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000;
45
46 // Container for current power status of all external devices.
47 // The key is a logical address a device and the value is current power status of it
48 // Whenever the action receives <Report Power Status> from a device,
49 // it removes an entry of the given device.
50 // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens,
51 // updates power status of all remaining devices into POWER_STATUS_UNKNOWN.
52 private final SparseIntArray mPowerStatus = new SparseIntArray();
53
54 PowerStatusMonitorAction(HdmiCecLocalDevice source) {
55 super(source);
56 }
57
58 @Override
59 boolean start() {
60 queryPowerStatus();
61 return true;
62 }
63
64 @Override
65 boolean processCommand(HdmiCecMessage cmd) {
Jinsuk Kim3f6755f2014-12-03 15:48:17 +090066 if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
67 && cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
68 return handleReportPowerStatus(cmd);
Jungshik Jang410ca9c2014-08-07 18:04:14 +090069 }
Jinsuk Kim3f6755f2014-12-03 15:48:17 +090070 return false;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090071 }
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 }
Jungshik Jang4480efa2014-09-04 17:08:34 +090080 int newStatus = cmd.getParams()[0] & 0xFF;
Jungshik Jang410ca9c2014-08-07 18:04:14 +090081 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.
Donghyun Chobc6e3722016-11-04 05:25:52 +0900125 if (error != SendMessageResult.SUCCESS) {
Jungshik Jang410ca9c2014-08-07 18:04:14 +0900126 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.
Shubanga3f59502018-06-05 16:32:53 -0700135 addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITORING_INTERNAL_MS);
Jungshik Jang410ca9c2014-08-07 18:04:14 +0900136 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}