2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.hdmi;
19 import android.hardware.hdmi.HdmiControlManager;
20 import android.hardware.hdmi.HdmiDeviceInfo;
21 import android.hardware.hdmi.IHdmiControlCallback;
22 import android.os.RemoteException;
23 import android.os.SystemProperties;
24 import android.util.Slog;
26 import com.android.internal.util.IndentingPrintWriter;
27 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
30 * Represent a logical device of type Playback residing in Android system.
32 final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
33 private static final String TAG = "HdmiCecLocalDevicePlayback";
35 private boolean mIsActiveSource = false;
37 HdmiCecLocalDevicePlayback(HdmiControlService service) {
38 super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
43 protected void onAddressAllocated(int logicalAddress, int reason) {
44 assertRunOnServiceThread();
45 mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
46 mAddress, mService.getPhysicalAddress(), mDeviceType));
51 protected int getPreferredAddress() {
52 assertRunOnServiceThread();
53 return SystemProperties.getInt(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
54 Constants.ADDR_UNREGISTERED);
59 protected void setPreferredAddress(int addr) {
60 assertRunOnServiceThread();
61 SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
62 String.valueOf(addr));
66 void oneTouchPlay(IHdmiControlCallback callback) {
67 assertRunOnServiceThread();
68 if (hasAction(OneTouchPlayAction.class)) {
69 Slog.w(TAG, "oneTouchPlay already in progress");
70 invokeCallback(callback, HdmiControlManager.RESULT_ALREADY_IN_PROGRESS);
74 // TODO: Consider the case of multiple TV sets. For now we always direct the command
75 // to the primary one.
76 OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
79 Slog.w(TAG, "Cannot initiate oneTouchPlay");
80 invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
83 addAndStartAction(action);
87 void queryDisplayStatus(IHdmiControlCallback callback) {
88 assertRunOnServiceThread();
89 if (hasAction(DevicePowerStatusAction.class)) {
90 Slog.w(TAG, "queryDisplayStatus already in progress");
91 invokeCallback(callback, HdmiControlManager.RESULT_ALREADY_IN_PROGRESS);
94 DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
95 Constants.ADDR_TV, callback);
97 Slog.w(TAG, "Cannot initiate queryDisplayStatus");
98 invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
101 addAndStartAction(action);
105 private void invokeCallback(IHdmiControlCallback callback, int result) {
106 assertRunOnServiceThread();
108 callback.onComplete(result);
109 } catch (RemoteException e) {
110 Slog.e(TAG, "Invoking callback failed:" + e);
116 void onHotplug(int portId, boolean connected) {
117 assertRunOnServiceThread();
118 mCecMessageCache.flushAll();
119 // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
120 if (connected && mService.isPowerStandbyOrTransient()) {
126 void markActiveSource() {
127 assertRunOnServiceThread();
128 mIsActiveSource = true;
133 protected boolean handleActiveSource(HdmiCecMessage message) {
134 assertRunOnServiceThread();
135 int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
136 mayResetActiveSource(physicalAddress);
137 return true; // Broadcast message.
140 private void mayResetActiveSource(int physicalAddress) {
141 if (physicalAddress != mService.getPhysicalAddress()) {
142 mIsActiveSource = false;
148 protected boolean handleSetStreamPath(HdmiCecMessage message) {
149 assertRunOnServiceThread();
150 int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
151 maySetActiveSource(physicalAddress);
152 maySendActiveSource();
153 wakeUpIfActiveSource();
154 return true; // Broadcast message.
157 // Samsung model, we tested, sends <RoutingChange> and <RequestActiveSource> consecutively,
158 // Then if there is no <ActiveSource> response, it will change the input to
159 // the internal source. To handle this, we'll set ActiveSource aggressively.
162 protected boolean handleRoutingChange(HdmiCecMessage message) {
163 assertRunOnServiceThread();
164 int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
165 maySetActiveSource(newPath);
166 return true; // Broadcast message.
171 protected boolean handleRoutingInformation(HdmiCecMessage message) {
172 assertRunOnServiceThread();
173 int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
174 maySetActiveSource(physicalAddress);
175 return true; // Broadcast message.
178 private void maySetActiveSource(int physicalAddress) {
179 if (physicalAddress == mService.getPhysicalAddress()) {
180 mIsActiveSource = true;
182 mIsActiveSource = false;
186 private void wakeUpIfActiveSource() {
187 if (mIsActiveSource && mService.isPowerStandbyOrTransient()) {
192 private void maySendActiveSource() {
193 if (mIsActiveSource) {
194 mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
195 mAddress, mService.getPhysicalAddress()));
201 protected boolean handleRequestActiveSource(HdmiCecMessage message) {
202 assertRunOnServiceThread();
203 maySendActiveSource();
204 return true; // Broadcast message.
209 protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
210 super.disableDevice(initiatedByCec, callback);
212 assertRunOnServiceThread();
213 if (!initiatedByCec && mIsActiveSource) {
214 mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
215 mAddress, mService.getPhysicalAddress()));
217 mIsActiveSource = false;
218 checkIfPendingActionsCleared();
222 protected void dump(final IndentingPrintWriter pw) {
224 pw.println("mIsActiveSource: " + mIsActiveSource);