HdmiCecFeatureAction.java revision c516d65fd96cdc39f9935ddb80d26ee6499a77bf
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/**
31c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
32c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
33c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
34c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * more than one command. {@link FeatureAction} represents the life cycle of the communication,
35c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * manages the state as the process progresses, and if necessary, returns the result
36c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * to the caller which initiates the action, through the callback given at the creation
37c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * of the object. All the actual action classes inherit FeatureAction.
38c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
39c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * <p>More than one FeatureAction objects can be up and running simultaneously,
4079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command
41c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * arriving from the bus, and either consumes it if the command is what the action expects,
42c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * or yields it to other action.
43c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim *
44c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Declared as package private, accessed by {@link HdmiControlService} only.
45c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */
46c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimabstract class FeatureAction {
47c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    private static final String TAG = "FeatureAction";
48c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
49c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Timer handler message used for timeout event
50c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected static final int MSG_TIMEOUT = 100;
51c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
52c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Default state used in common by all the feature actions.
53c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected static final int STATE_NONE = 0;
54c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
55c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Internal state indicating the progress of action.
56c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected int mState = STATE_NONE;
57c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
5879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final HdmiControlService mService;
5979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    private final HdmiCecLocalDevice mSource;
60c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
61c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Timer that manages timeout events.
62c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected ActionTimer mActionTimer;
63c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
64c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    private ArrayList<Pair<FeatureAction, Runnable>> mOnFinishedCallbacks;
65c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
6679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    FeatureAction(HdmiCecLocalDevice source) {
6779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource = source;
6879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mService = mSource.getService();
6979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mActionTimer = createActionTimer(mService.getServiceLooper());
70c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
71c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
72c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    @VisibleForTesting
73c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    void setActionTimer(ActionTimer actionTimer) {
74c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        mActionTimer = actionTimer;
75c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
76c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
77c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
78c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Called right after the action is created. Initialization or first step to take
79c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * for the action can be done in this method.
80c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
81c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @return true if the operation is successful; otherwise false.
82c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
83c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract boolean start();
84c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
85c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
86c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Process the command. Called whenever a new command arrives.
87c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
88c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @param cmd command to process
89c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @return true if the command was consumed in the process; Otherwise false, which
90c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *          indicates that the command shall be handled by other actions.
91c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
92c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract boolean processCommand(HdmiCecMessage cmd);
93c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
94c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
95c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Called when the action should handle the timer event it created before.
96c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
97c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * <p>CEC standard mandates each command transmission should be responded within
98c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * certain period of time. The method is called when the timer it created as it transmitted
99c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * a command gets expired. Inner logic should take an appropriate action.
100c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     *
101c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * @param state the state associated with the time when the timer was created
102c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
103c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    abstract void handleTimerEvent(int state);
104c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
105c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
106c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Timer handler interface used for FeatureAction classes.
107c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
108c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    interface ActionTimer {
109c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        /**
110c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * Send a timer message.
111c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         *
112c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * Also carries the state of the action when the timer is created. Later this state is
113c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * compared to the one the action is in when it receives the timer to let the action tell
114c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * the right timer to handle.
115c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         *
116c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * @param state state of the action is in
117c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         * @param delayMillis amount of delay for the timer
118c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim         */
119c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        void sendTimerMessage(int state, long delayMillis);
12067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
12167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        /**
12267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang         * Removes any pending timer message.
12367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang         */
12467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        void clearTimerMessage();
125c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
126c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
127c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    private class ActionTimerHandler extends Handler implements ActionTimer {
128c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
129c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public ActionTimerHandler(Looper looper) {
130c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            super(looper);
131c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
132c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
133c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        @Override
134c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public void sendTimerMessage(int state, long delayMillis) {
135b0674f0f7c04b707ca7b11f5700bdb9e51b61872Jinsuk Kim            // The third argument(0) is not used.
136b0674f0f7c04b707ca7b11f5700bdb9e51b61872Jinsuk Kim            sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state, 0), delayMillis);
137c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
138c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
139c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        @Override
14067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        public void clearTimerMessage() {
14167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            removeMessages(MSG_TIMEOUT);
14267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
14367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
14467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        @Override
145c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        public void handleMessage(Message msg) {
146c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            switch (msg.what) {
147c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            case MSG_TIMEOUT:
148c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                handleTimerEvent(msg.arg1);
149c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                break;
150c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            default:
151c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                Slog.w(TAG, "Unsupported message:" + msg.what);
152c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim                break;
153c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim            }
154c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        }
155c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
156c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
157c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    private ActionTimer createActionTimer(Looper looper) {
158c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        return new ActionTimerHandler(looper);
159c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
160c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
161c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // Add a new timer. The timer event will come to mActionTimer.handleMessage() in
162c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    // delayMillis.
163c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected void addTimer(int state, int delayMillis) {
164c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim        mActionTimer.sendTimerMessage(state, delayMillis);
165c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
166c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
167d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd) {
168d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd);
169d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
170d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
171d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    protected final void sendCommand(HdmiCecMessage cmd,
172d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            HdmiControlService.SendMessageCallback callback) {
173d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        mService.sendCecCommand(cmd, callback);
17467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
17567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
17679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final void addAndStartAction(FeatureAction action) {
17779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.addAndStartAction(action);
17879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
17979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
18179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getActions(clazz);
18279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecMessageCache getCecMessageCache() {
18579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getCecMessageCache();
18679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
18779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
18879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    /**
18979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * Remove the action from the action queue. This is called after the action finishes
19079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * its role.
19179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     *
19279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param action
19379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     */
19479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final void removeAction(FeatureAction action) {
19579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeAction(action);
19679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
19779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
19879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) {
19979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, null);
20079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
20379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            final FeatureAction exception) {
20479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        mSource.removeActionExcept(clazz, exception);
20579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
20679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
20779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final void pollDevices(DevicePollingCallback callback, int pickStrategy,
20879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            int retryCount) {
2091de514256fd3015cf45256f3198ab5472024af9bJungshik Jang        mService.pollDevices(callback, getSourceAddress(), pickStrategy, retryCount);
21079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
21179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
21267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    /**
21367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * Clean up action's state.
21467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     *
21567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * <p>Declared as package-private. Only {@link HdmiControlService} can access it.
21667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     */
21767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    void clear() {
21867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mState = STATE_NONE;
21967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // Clear all timers.
22067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mActionTimer.clearTimerMessage();
221c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
222c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
223c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    /**
224c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     * Finish up the action. Reset the state, and remove itself from the action queue.
225c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim     */
226c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    protected void finish() {
227c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        finish(true);
228c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
229c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
230c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    void finish(boolean removeSelf) {
23167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        clear();
232c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (removeSelf) {
233c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            removeAction(this);
234c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
235c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks != null) {
236c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            for (Pair<FeatureAction, Runnable> actionCallbackPair: mOnFinishedCallbacks) {
237c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                if (actionCallbackPair.first.mState != STATE_NONE) {
238c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                    actionCallbackPair.second.run();
239c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo                }
240c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            }
241c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = null;
242c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
243c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
244c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim
24579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevice localDevice() {
24679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource;
24779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
24879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
24979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDevicePlayback playback() {
25079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDevicePlayback) mSource;
25179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final HdmiCecLocalDeviceTv tv() {
25479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return (HdmiCecLocalDeviceTv) mSource;
25579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
25679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
25779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourceAddress() {
25879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getLogicalAddress();
25979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    }
26079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang
26179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    protected final int getSourcePath() {
26279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        return mSource.getDeviceInfo().getPhysicalAddress();
263c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim    }
2648fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang
265c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) {
2668fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
2678fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang                getSourceAddress(), targetAddress, uiCommand));
2688fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
2698fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang                getSourceAddress(), targetAddress));
2708fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang    }
271c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo
272c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    protected final void addOnFinishedCallback(FeatureAction action, Runnable runnable) {
273c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        if (mOnFinishedCallbacks == null) {
274c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo            mOnFinishedCallbacks = new ArrayList<>();
275c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        }
276c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo        mOnFinishedCallbacks.add(Pair.create(action, runnable));
277c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo    }
278c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim}
279