ActiveSourceHandler.java revision a062a9339add79a84862a34e363e3e454a6ec435
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.annotation.Nullable;
20import android.hardware.hdmi.IHdmiControlCallback;
21import android.hardware.hdmi.HdmiCec;
22import android.hardware.hdmi.HdmiCecDeviceInfo;
23import android.hardware.hdmi.HdmiCecMessage;
24import android.os.RemoteException;
25import android.util.Slog;
26
27/**
28 * Handles CEC command <Active Source>.
29 * <p>
30 * Used by feature actions that need to handle the command in their flow.
31 */
32final class ActiveSourceHandler {
33    private static final String TAG = "ActiveSourceHandler";
34
35    private final HdmiCecLocalDevice mSource;
36    private final HdmiControlService mService;
37    @Nullable
38    private final IHdmiControlCallback mCallback;
39
40    static ActiveSourceHandler create(HdmiCecLocalDevice source,
41            IHdmiControlCallback callback) {
42        if (source == null) {
43            Slog.e(TAG, "Wrong arguments");
44            return null;
45        }
46        return new ActiveSourceHandler(source, callback);
47    }
48
49    private ActiveSourceHandler(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
50        mSource = source;
51        mService = mSource.getService();
52        mCallback = callback;
53    }
54
55    /**
56     * Handles the incoming active source command.
57     *
58     * @param deviceLogicalAddress logical address of the device to be the active source
59     * @param routingPath routing path of the device to be the active source
60     */
61    void process(int deviceLogicalAddress, int routingPath) {
62        if (getSourcePath() == routingPath && mSource.getActiveSource() == getSourceAddress()) {
63            invokeCallback(HdmiCec.RESULT_SUCCESS);
64            return;
65        }
66        HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress);
67        if (device == null) {
68            // "New device action" initiated by <Active Source> does not require
69            // "Routing change action".
70            mSource.addAndStartAction(new NewDeviceAction(mSource, deviceLogicalAddress,
71                    routingPath, false));
72        }
73
74        if (!mSource.isInPresetInstallationMode()) {
75            int prevActiveInput = mSource.getActivePortId();
76            mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
77            if (prevActiveInput != mSource.getActivePortId()) {
78                // TODO: change port input here.
79            }
80            invokeCallback(HdmiCec.RESULT_SUCCESS);
81        } else {
82            // TV is in a mode that should keep its current source/input from
83            // being changed for its operation. Reclaim the active source
84            // or switch the port back to the one used for the current mode.
85            if (mSource.getActiveSource() == getSourceAddress()) {
86                HdmiCecMessage activeSource =
87                        HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
88                                getSourcePath());
89                mService.sendCecCommand(activeSource);
90                mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
91                invokeCallback(HdmiCec.RESULT_SUCCESS);
92            } else {
93                int activePath = mSource.getActivePath();
94                mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
95                        routingPath, activePath));
96                // TODO: Start port select action here
97                // PortSelectAction action = new PortSelectAction(mService, getSourceAddress(),
98                // activePath, mCallback);
99                // mService.addActionAndStart(action);
100            }
101        }
102    }
103
104    private final int getSourceAddress() {
105        return mSource.getDeviceInfo().getLogicalAddress();
106    }
107
108    private final int getSourcePath() {
109        return mSource.getDeviceInfo().getPhysicalAddress();
110    }
111
112    private void invokeCallback(int result) {
113        if (mCallback == null) {
114            return;
115        }
116        try {
117            mCallback.onComplete(result);
118        } catch (RemoteException e) {
119            Slog.e(TAG, "Callback failed:" + e);
120        }
121    }
122}
123