1a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim/*
2a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Copyright (C) 2014 The Android Open Source Project
3a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim *
4a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License");
5a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * you may not use this file except in compliance with the License.
6a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * You may obtain a copy of the License at
7a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim *
8a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim *      http://www.apache.org/licenses/LICENSE-2.0
9a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim *
10a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Unless required by applicable law or agreed to in writing, software
11a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS,
12a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * See the License for the specific language governing permissions and
14a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * limitations under the License.
15a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim */
16a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
17a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimpackage com.android.server.hdmi;
18a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
19a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.annotation.Nullable;
20a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.hardware.hdmi.IHdmiControlCallback;
2161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo;
22c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager;
23a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.os.RemoteException;
24a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.util.Slog;
25a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
2672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
2772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim
28a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim/**
29a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Handles CEC command <Active Source>.
3079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>
318333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * Used by feature actions that need to handle the command in their flow. Only for TV
328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * local device.
33a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim */
34a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimfinal class ActiveSourceHandler {
35a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    private static final String TAG = "ActiveSourceHandler";
36a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    private final HdmiCecLocalDeviceTv mSource;
38a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    private final HdmiControlService mService;
3979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    @Nullable
4079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final IHdmiControlCallback mCallback;
41a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
428333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    static ActiveSourceHandler create(HdmiCecLocalDeviceTv source, IHdmiControlCallback callback) {
4379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        if (source == null) {
44a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            Slog.e(TAG, "Wrong arguments");
45a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            return null;
46a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
4779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return new ActiveSourceHandler(source, callback);
48a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
49a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
508333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim    private ActiveSourceHandler(HdmiCecLocalDeviceTv source, IHdmiControlCallback callback) {
5179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource = source;
5279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mService = mSource.getService();
53a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        mCallback = callback;
54a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
55a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
56a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    /**
57a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     * Handles the incoming active source command.
58a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     *
5972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim     * @param newActive new active source information
60bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim     * @param deviceType device type of the new active source
61a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim     */
62bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim    void process(ActiveSource newActive, int deviceType) {
638333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        // Seq #17
648333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim        HdmiCecLocalDeviceTv tv = mSource;
6561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang        HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
66a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        if (device == null) {
67bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim            tv.startNewDeviceAction(newActive, deviceType);
68a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
69a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
704d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim        if (!tv.isProhibitMode()) {
7172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            tv.updateActiveSource(newActive);
727c3a95633d307c4be30c9dbbf1071063aa7a3c64Jinsuk Kim            boolean notifyInputChange = (mCallback == null);
737c3a95633d307c4be30c9dbbf1071063aa7a3c64Jinsuk Kim            tv.updateActiveInput(newActive.physicalAddress, notifyInputChange);
74c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim            invokeCallback(HdmiControlManager.RESULT_SUCCESS);
75a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        } else {
76a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            // TV is in a mode that should keep its current source/input from
77a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            // being changed for its operation. Reclaim the active source
78a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            // or switch the port back to the one used for the current mode.
797c3a95633d307c4be30c9dbbf1071063aa7a3c64Jinsuk Kim            ActiveSource current = tv.getActiveSource();
8072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim            if (current.logicalAddress == getSourceAddress()) {
8172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
8272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                        current.logicalAddress, current.physicalAddress);
8372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                mService.sendCecCommand(activeSourceCommand);
8472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim                tv.updateActiveSource(current);
85c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim                invokeCallback(HdmiControlManager.RESULT_SUCCESS);
86a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            } else {
87546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim                tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true,
88546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim                        mCallback);
89a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            }
90a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
91a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
92a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim
9379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final int getSourceAddress() {
9479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getLogicalAddress();
9579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
9679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
97a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    private void invokeCallback(int result) {
98a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        if (mCallback == null) {
99a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            return;
100a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
101a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        try {
102a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            mCallback.onComplete(result);
103a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        } catch (RemoteException e) {
104a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim            Slog.e(TAG, "Callback failed:" + e);
105a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        }
106a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    }
107a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim}
108