HdmiCecLocalDevicePlayback.java revision 2849b7ccd1cf973f862dd9b95355afbc9ca9268b
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 */
16
17package com.android.server.hdmi;
18
19import android.hardware.hdmi.HdmiDeviceInfo;
20import android.hardware.hdmi.HdmiControlManager;
21import android.hardware.hdmi.IHdmiControlCallback;
22import android.os.RemoteException;
23import android.os.SystemProperties;
24import android.util.Slog;
25
26import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
27
28/**
29 * Represent a logical device of type Playback residing in Android system.
30 */
31final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
32    private static final String TAG = "HdmiCecLocalDevicePlayback";
33
34    private boolean mIsActiveSource = false;
35
36    HdmiCecLocalDevicePlayback(HdmiControlService service) {
37        super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
38    }
39
40    @Override
41    @ServiceThreadOnly
42    protected void onAddressAllocated(int logicalAddress, int reason) {
43        assertRunOnServiceThread();
44        mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
45                mAddress, mService.getPhysicalAddress(), mDeviceType));
46        if (reason == HdmiControlService.INITIATED_BY_SCREEN_ON) {
47            oneTouchPlay(new IHdmiControlCallback.Stub() {
48                @Override public void onComplete(int result) throws RemoteException {}
49            });
50        }
51    }
52
53    @Override
54    @ServiceThreadOnly
55    protected int getPreferredAddress() {
56        assertRunOnServiceThread();
57        return SystemProperties.getInt(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
58                Constants.ADDR_UNREGISTERED);
59    }
60
61    @Override
62    @ServiceThreadOnly
63    protected void setPreferredAddress(int addr) {
64        assertRunOnServiceThread();
65        SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
66                String.valueOf(addr));
67    }
68
69    @ServiceThreadOnly
70    void oneTouchPlay(IHdmiControlCallback callback) {
71        assertRunOnServiceThread();
72        if (hasAction(OneTouchPlayAction.class)) {
73            Slog.w(TAG, "oneTouchPlay already in progress");
74            invokeCallback(callback, HdmiControlManager.RESULT_ALREADY_IN_PROGRESS);
75            return;
76        }
77
78        // TODO: Consider the case of multiple TV sets. For now we always direct the command
79        //       to the primary one.
80        OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
81                callback);
82        if (action == null) {
83            Slog.w(TAG, "Cannot initiate oneTouchPlay");
84            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
85            return;
86        }
87        addAndStartAction(action);
88    }
89
90    @ServiceThreadOnly
91    void queryDisplayStatus(IHdmiControlCallback callback) {
92        assertRunOnServiceThread();
93        if (hasAction(DevicePowerStatusAction.class)) {
94            Slog.w(TAG, "queryDisplayStatus already in progress");
95            invokeCallback(callback, HdmiControlManager.RESULT_ALREADY_IN_PROGRESS);
96            return;
97        }
98        DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
99                Constants.ADDR_TV, callback);
100        if (action == null) {
101            Slog.w(TAG, "Cannot initiate queryDisplayStatus");
102            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
103            return;
104        }
105        addAndStartAction(action);
106    }
107
108    @ServiceThreadOnly
109    private void invokeCallback(IHdmiControlCallback callback, int result) {
110        assertRunOnServiceThread();
111        try {
112            callback.onComplete(result);
113        } catch (RemoteException e) {
114            Slog.e(TAG, "Invoking callback failed:" + e);
115        }
116    }
117
118    @Override
119    @ServiceThreadOnly
120    void onHotplug(int portId, boolean connected) {
121        assertRunOnServiceThread();
122        mCecMessageCache.flushAll();
123        mIsActiveSource = false;
124        if (connected && mService.isPowerStandbyOrTransient()) {
125            mService.wakeUp();
126        }
127    }
128
129    @ServiceThreadOnly
130    void markActiveSource() {
131        assertRunOnServiceThread();
132        mIsActiveSource = true;
133    }
134
135    @Override
136    @ServiceThreadOnly
137    protected boolean handleActiveSource(HdmiCecMessage message) {
138        assertRunOnServiceThread();
139        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
140        if (physicalAddress != mService.getPhysicalAddress()) {
141            mIsActiveSource = false;
142            if (mService.isPowerOnOrTransient()) {
143                mService.nap();
144            }
145            return true;
146        }
147        return false;
148    }
149
150    @Override
151    @ServiceThreadOnly
152    protected boolean handleSetStreamPath(HdmiCecMessage message) {
153        assertRunOnServiceThread();
154        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
155        if (physicalAddress == mService.getPhysicalAddress()) {
156            if (mService.isPowerStandbyOrTransient()) {
157                mService.wakeUp();
158            }
159            return true;
160        }
161        return false;
162    }
163
164    @Override
165    @ServiceThreadOnly
166    protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
167        super.disableDevice(initiatedByCec, callback);
168
169        assertRunOnServiceThread();
170        if (!initiatedByCec && mIsActiveSource) {
171            mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
172                    mAddress, mService.getPhysicalAddress()));
173        }
174        mIsActiveSource = false;
175        checkIfPendingActionsCleared();
176    }
177}
178