HdmiCecFeatureAction.java revision 7df52862dae1fa33c84725c613b0d9b88c1b28b6
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    /**
76c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Called right after the action is created. Initialization or first step to take
77c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * for the action can be done in this method.
78c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
79c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @return true if the operation is successful; otherwise false.
80c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
81c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract boolean start();
82c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
83c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
84c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Process the command. Called whenever a new command arrives.
85c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
86c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @param cmd command to process
87c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @return true if the command was consumed in the process; Otherwise false, which
88c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *          indicates that the command shall be handled by other actions.
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
165d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd) {
166d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd);
167d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
168d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
169d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd,
170d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            HdmiControlService.SendMessageCallback callback) {
171d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd, callback);
17267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
17367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
174b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void addAndStartAction(HdmiCecFeatureAction action) {
17579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.addAndStartAction(action);
17679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
17779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
178b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) {
17979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getActions(clazz);
18079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecMessageCache getCecMessageCache() {
18379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getCecMessageCache();
18479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
18779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Remove the action from the action queue. This is called after the action finishes
18879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * its role.
18979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
19079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param action
19179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
192b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void removeAction(HdmiCecFeatureAction action) {
19379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeAction(action);
19479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
19579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
196b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) {
19779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, null);
19879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
19979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
200b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz,
201b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang            final HdmiCecFeatureAction exception) {
20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, exception);
20379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
20579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final void pollDevices(DevicePollingCallback callback, int pickStrategy,
20679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            int retryCount) {
2071de514256fd3015cf45256f3198ab5472024af9bJungshik Jang        mService.pollDevices(callback, getSourceAddress(), pickStrategy, retryCount);
20879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
21067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    /**
21167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * Clean up action's state.
21267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     *
21367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * <p>Declared as package-private. Only {@link HdmiControlService} can access it.
21467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     */
21567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    void clear() {
21667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mState = STATE_NONE;
21767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // Clear all timers.
21867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mActionTimer.clearTimerMessage();
219c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
220c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
221c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
222c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Finish up the action. Reset the state, and remove itself from the action queue.
223c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
224c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected void finish() {
225c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        finish(true);
226c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
227c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
228c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    void finish(boolean removeSelf) {
22967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        clear();
230c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (removeSelf) {
231c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            removeAction(this);
232c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
233c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks != null) {
234b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang            for (Pair<HdmiCecFeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
235c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                if (actionCallbackPair.first.mState != STATE_NONE) {
236c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                    actionCallbackPair.second.run();
237c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                }
238c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            }
239c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = null;
240c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
241c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
242c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
24379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevice localDevice() {
24479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource;
24579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
24679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
24779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevicePlayback playback() {
24879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDevicePlayback) mSource;
24979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDeviceTv tv() {
25279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDeviceTv) mSource;
25379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourceAddress() {
25679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getLogicalAddress();
25779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourcePath() {
26079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getPhysicalAddress();
261c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
2628fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang
263c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) {
2648fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
2658fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang                getSourceAddress(), targetAddress, uiCommand));
2668fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
2678fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang                getSourceAddress(), targetAddress));
2688fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang    }
269c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
270b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang    protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) {
271c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks == null) {
272c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = new ArrayList<>();
273c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
274c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        mOnFinishedCallbacks.add(Pair.create(action, runnable));
275c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
276c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim}
277