1c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim/*
2c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Copyright (C) 2014 The Android Open Source Project
3c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
4c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License");
5c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * you may not use this file except in compliance with the License.
6c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * You may obtain a copy of the License at
7c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
8c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *      http://www.apache.org/licenses/LICENSE-2.0
9c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
10c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Unless required by applicable law or agreed to in writing, software
11c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS,
12c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * See the License for the specific language governing permissions and
14c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * limitations under the License.
15c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */
16c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimpackage com.android.server.hdmi;
17c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
18c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.os.Handler;
19c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.os.Looper;
20c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.os.Message;
21c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heoimport android.util.Pair;
22c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.util.Slog;
23c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
24c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport com.android.internal.annotations.VisibleForTesting;
2579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
2679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
27c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heoimport java.util.ArrayList;
2879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.List;
29c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
30c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim/**
317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang * Encapsulates a sequence of CEC command exchange for a certain feature.
32b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * <p>
337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang * Many CEC features are accomplished by CEC devices on the bus exchanging more than one
34b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * command. {@link HdmiCecFeatureAction} represents the life cycle of the communication, manages the
35b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * state as the process progresses, and if necessary, returns the result to the caller which
36b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * initiates the action, through the callback given at the creation of the object. All the actual
37b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * action classes inherit FeatureAction.
38b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * <p>
39b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * More than one FeatureAction objects can be up and running simultaneously, maintained by
40b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * {@link HdmiCecLocalDevice}. Each action is passed a new command arriving from the bus, and either
41b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * consumes it if the command is what the action expects, or yields it to other action. Declared as
42b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * package private, accessed by {@link HdmiControlService} only.
43c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */
44b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jangabstract class HdmiCecFeatureAction {
457df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang    private static final String TAG = "HdmiCecFeatureAction";
46c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
47c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Timer handler message used for timeout event
48c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected static final int MSG_TIMEOUT = 100;
49c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
50c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Default state used in common by all the feature actions.
51c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected static final int STATE_NONE = 0;
52c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
53c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Internal state indicating the progress of action.
54c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected int mState = STATE_NONE;
55c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
5679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final HdmiControlService mService;
5779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final HdmiCecLocalDevice mSource;
58c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
59c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Timer that manages timeout events.
60c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected ActionTimer mActionTimer;
61c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
62b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    private ArrayList<Pair<HdmiCecFeatureAction, Runnable>> mOnFinishedCallbacks;
63c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
64b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    HdmiCecFeatureAction(HdmiCecLocalDevice source) {
6579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource = source;
6679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mService = mSource.getService();
6779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActionTimer = createActionTimer(mService.getServiceLooper());
68c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
69c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
70c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    @VisibleForTesting
71c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    void setActionTimer(ActionTimer actionTimer) {
72c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        mActionTimer = actionTimer;
73c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
74c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
75c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
766f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim     * Called after the action is created. Initialization or first step to take
776f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim     * for the action can be done in this method. Shall update {@code mState} to
786f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim     * indicate that the action has started.
79c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
80c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @return true if the operation is successful; otherwise false.
81c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
82c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract boolean start();
83c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
84c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
85c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Process the command. Called whenever a new command arrives.
86c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
87c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @param cmd command to process
885352081c662299b618335bf3024058fa04ef2dfdJungshik Jang     * @return true if the command was consumed in the process; Otherwise false.
89c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
90c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract boolean processCommand(HdmiCecMessage cmd);
91c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
92c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
93c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Called when the action should handle the timer event it created before.
94c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
95c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * <p>CEC standard mandates each command transmission should be responded within
96c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * certain period of time. The method is called when the timer it created as it transmitted
97c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * a command gets expired. Inner logic should take an appropriate action.
98c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
99c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @param state the state associated with the time when the timer was created
100c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
101c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract void handleTimerEvent(int state);
102c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
103c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
104c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Timer handler interface used for FeatureAction classes.
105c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
106c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    interface ActionTimer {
107c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        /**
108c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * Send a timer message.
109c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         *
110c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * Also carries the state of the action when the timer is created. Later this state is
111c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * compared to the one the action is in when it receives the timer to let the action tell
112c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * the right timer to handle.
113c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         *
114c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * @param state state of the action is in
115c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * @param delayMillis amount of delay for the timer
116c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         */
117c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        void sendTimerMessage(int state, long delayMillis);
11867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
11967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        /**
12067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang         * Removes any pending timer message.
12167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang         */
12267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        void clearTimerMessage();
123c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
124c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
125c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    private class ActionTimerHandler extends Handler implements ActionTimer {
126c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
127c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public ActionTimerHandler(Looper looper) {
128c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            super(looper);
129c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
130c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
131c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        @Override
132c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public void sendTimerMessage(int state, long delayMillis) {
133b0674f0f7c04b707ca7b11f5700bdb9e51b61872Jinsuk Kim            // The third argument(0) is not used.
134b0674f0f7c04b707ca7b11f5700bdb9e51b61872Jinsuk Kim            sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state, 0), delayMillis);
135c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
136c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
137c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        @Override
13867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        public void clearTimerMessage() {
13967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            removeMessages(MSG_TIMEOUT);
14067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
14167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
14267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        @Override
143c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public void handleMessage(Message msg) {
144c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            switch (msg.what) {
145c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            case MSG_TIMEOUT:
146c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                handleTimerEvent(msg.arg1);
147c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                break;
148c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            default:
149c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                Slog.w(TAG, "Unsupported message:" + msg.what);
150c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                break;
151c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            }
152c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
153c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
154c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
155c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    private ActionTimer createActionTimer(Looper looper) {
156c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        return new ActionTimerHandler(looper);
157c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
158c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
159c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Add a new timer. The timer event will come to mActionTimer.handleMessage() in
160c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // delayMillis.
161c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected void addTimer(int state, int delayMillis) {
162c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        mActionTimer.sendTimerMessage(state, delayMillis);
163c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
164c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
1656f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim    boolean started() {
1666f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim        return mState != STATE_NONE;
1676f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim    }
1686f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim
169d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd) {
170d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd);
171d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
172d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
173d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd,
174d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            HdmiControlService.SendMessageCallback callback) {
175d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd, callback);
17667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
17767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
178b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void addAndStartAction(HdmiCecFeatureAction action) {
17979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.addAndStartAction(action);
18079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
182b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
18379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getActions(clazz);
18479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecMessageCache getCecMessageCache() {
18779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getCecMessageCache();
18879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
19079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
19179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Remove the action from the action queue. This is called after the action finishes
19279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * its role.
19379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
19479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param action
19579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
196b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void removeAction(HdmiCecFeatureAction action) {
19779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeAction(action);
19879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
19979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
200b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
20179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, null);
20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
204b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
205b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang            final HdmiCecFeatureAction exception) {
20679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, exception);
20779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
20979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final void pollDevices(DevicePollingCallback callback, int pickStrategy,
21079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            int retryCount) {
2111de514256fd3015cf45256f3198ab5472024af9bJungshik Jang        mService.pollDevices(callback, getSourceAddress(), pickStrategy, retryCount);
21279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
21379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
21467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    /**
21567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * Clean up action's state.
21667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     *
21767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * <p>Declared as package-private. Only {@link HdmiControlService} can access it.
21867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     */
21967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    void clear() {
22067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mState = STATE_NONE;
22167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // Clear all timers.
22267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mActionTimer.clearTimerMessage();
223c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
224c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
225c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
226c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Finish up the action. Reset the state, and remove itself from the action queue.
227c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
228c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected void finish() {
229c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        finish(true);
230c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
231c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
232c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    void finish(boolean removeSelf) {
23367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        clear();
234c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (removeSelf) {
235c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            removeAction(this);
236c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
237c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks != null) {
238b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang            for (Pair<HdmiCecFeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
239c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                if (actionCallbackPair.first.mState != STATE_NONE) {
240c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                    actionCallbackPair.second.run();
241c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                }
242c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            }
243c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = null;
244c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
245c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
246c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
24779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevice localDevice() {
24879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource;
24979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevicePlayback playback() {
25279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDevicePlayback) mSource;
25379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDeviceTv tv() {
25679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDeviceTv) mSource;
25779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourceAddress() {
26079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getLogicalAddress();
26179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
26279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
26379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourcePath() {
26479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getPhysicalAddress();
265c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
2668fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang
267c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) {
2682e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang        mSource.sendUserControlPressedAndReleased(targetAddress, uiCommand);
2698fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang    }
270c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
271b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) {
272c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks == null) {
273c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = new ArrayList<>();
274c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
275c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        mOnFinishedCallbacks.add(Pair.create(action, runnable));
276c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
277c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim}
278