HdmiControlService.java revision cc5ef8c918e96516a5c51cc40735a1b8a24d8497
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 21a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport android.hardware.hdmi.HdmiCec; 22c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 23c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecMessage; 24d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 25d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 26d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 2767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 2978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 30e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 3178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 3378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 3478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport com.android.internal.annotations.GuardedBy; 350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 36cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; 370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 3878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 3967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport java.util.Iterator; 4067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport java.util.LinkedList; 4102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 42a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport java.util.Locale; 43a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 5278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 5378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 54ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_SUCCESS = 0; 55ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_NAK = -1; 56ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_FAILURE = -2; 57ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo 58d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 59d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 60d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 61d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 62d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 63d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 64d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 65ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 66ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 67ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 68ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 70d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 7302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 7402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 7502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 7602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 7702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 7802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 7902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 8002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 8102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 9067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // A collection of FeatureAction. 9167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Note that access to this collection should happen in service thread. 9267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private final LinkedList<FeatureAction> mActions = new LinkedList<>(); 9367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 9478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 9578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 9678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Type of logical devices hosted in the system. 9878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @GuardedBy("mLock") 9978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final int[] mLocalDevices; 10078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 10278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 10378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 10478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 10678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 10778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 10878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 11567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Whether ARC is "enabled" or not. 11667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: it may need to hold lock if it's accessed from others. 11767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private boolean mArcStatusEnabled = false; 11867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 11967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Handler running on service thread. It's used to run a task in service thread. 12067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private Handler mHandler = new Handler(); 12167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 12478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mLocalDevices = getContext().getResources().getIntArray( 12578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType); 1260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1302f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 131e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 132a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim if (mCecController != null) { 13378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mCecController.initializeLocalDevices(mLocalDevices); 134a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 1350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 1360792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 138e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 1390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 1400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 1410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 14278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 14378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Publish the BinderService 14478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 146e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 147e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 148e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 149e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 150e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 151e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 152e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 153e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 154e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 155e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 156e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 157e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 158e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 159e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 160e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 161e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 162e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 16367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 164e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 165c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 166c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 16767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Add and start a new {@link FeatureAction} to the action queue. 168c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 16967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param action {@link FeatureAction} to add and start 170c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 17167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void addAndStartAction(final FeatureAction action) { 17267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: may need to check the number of stale actions. 17367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang runOnServiceThread(new Runnable() { 17467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang @Override 17567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang public void run() { 17667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mActions.add(action); 17767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang action.start(); 17867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 17967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang }); 180c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 181c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 1827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // See if we have an action of a given type in progress. 1837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private <T extends FeatureAction> boolean hasAction(final Class<T> clazz) { 1847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim for (FeatureAction action : mActions) { 1857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action.getClass().equals(clazz)) { 1867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return true; 1877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 1887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 1897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return false; 1907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 1917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 192c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 193c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Remove the given {@link FeatureAction} object from the action queue. 194c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 19567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param action {@link FeatureAction} to remove 196c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 19767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void removeAction(final FeatureAction action) { 19867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang runOnServiceThread(new Runnable() { 19967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang @Override 20067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang public void run() { 20167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mActions.remove(action); 20267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 20367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang }); 20467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 20567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 20667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // Remove all actions matched with the given Class type. 20767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private <T extends FeatureAction> void removeAction(final Class<T> clazz) { 20867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang runOnServiceThread(new Runnable() { 20967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang @Override 21067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang public void run() { 21167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang Iterator<FeatureAction> iter = mActions.iterator(); 21267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang while (iter.hasNext()) { 21367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang FeatureAction action = iter.next(); 21467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang if (action.getClass().equals(clazz)) { 21567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang action.clear(); 21667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mActions.remove(action); 21767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 21867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 21967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 22067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang }); 22167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 22267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 22367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void runOnServiceThread(Runnable runnable) { 22467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 22567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 22667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 22767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 22867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Change ARC status into the given {@code enabled} status. 22967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 23067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @return {@code true} if ARC was in "Enabled" status 23167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 23267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang boolean setArcStatus(boolean enabled) { 23367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang boolean oldStatus = mArcStatusEnabled; 23467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // 1. Enable/disable ARC circuit. 23567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: call set_audio_return_channel of hal interface. 23667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 23767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // 2. Update arc status; 23867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mArcStatusEnabled = enabled; 23967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return oldStatus; 240c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 241c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 242c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 243c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 244c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 245c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 246d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 247c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 248d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 249d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 250d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 251d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 252d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 253d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 254c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 255c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 256c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 257c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Add a new {@link HdmiCecDeviceInfo} to controller. 258c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 259c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param deviceInfo new device information object to add 260c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 261c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim void addDeviceInfo(HdmiCecDeviceInfo deviceInfo) { 262c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim // TODO: Implement this. 263c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 264a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 265a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 266a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // Commands that queries system information replies directly instead 267a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // of creating FeatureAction because they are state-less. 268a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang switch (message.getOpcode()) { 269a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang case HdmiCec.MESSAGE_GET_MENU_LANGUAGE: 270a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang handleGetMenuLanguage(message); 271a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return true; 272be9cd8eb3fe64a572f9c7dfc41f04defd46a752dJungshik Jang case HdmiCec.MESSAGE_GIVE_OSD_NAME: 273be9cd8eb3fe64a572f9c7dfc41f04defd46a752dJungshik Jang handleGiveOsdName(message); 274a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return true; 275a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS: 276a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang handleGivePhysicalAddress(message); 277a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return true; 278a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID: 279a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang handleGiveDeviceVendorId(message); 280a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return true; 281a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang case HdmiCec.MESSAGE_GET_CEC_VERSION: 282a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang handleGetCecVersion(message); 283a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return true; 28467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang case HdmiCec.MESSAGE_INITIATE_ARC: 28567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang handleInitiateArc(message); 28667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return true; 28767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang case HdmiCec.MESSAGE_TERMINATE_ARC: 28867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang handleTerminateArc(message); 28967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return true; 290a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // TODO: Add remaining system information query such as 291a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // <Give Device Power Status> and <Request Active Source> handler. 292a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang default: 293a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang Slog.w(TAG, "Unsupported cec command:" + message.toString()); 294a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return false; 295a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 296a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 297a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 29867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 29967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 30067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 30167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param port hdmi port number where hot plug event issued. 30267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 30367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 30467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 30567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: Start "RequestArcInitiationAction" if ARC port. 30667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 30767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 30802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 30902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 31002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 31102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 31202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 31302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 31402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 31502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void pollDevices(DevicePollingCallback callback, int retryCount) { 31602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang mCecController.pollDevices(callback, retryCount); 31702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 31802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 31967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void handleInitiateArc(HdmiCecMessage message){ 32067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // In case where <Initiate Arc> is started by <Request ARC Initiation> 32167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // need to clean up RequestArcInitiationAction. 32267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang removeAction(RequestArcInitiationAction.class); 32367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 32467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang message.getDestination(), message.getSource(), true); 32567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang addAndStartAction(action); 32667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 32767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 32867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang private void handleTerminateArc(HdmiCecMessage message) { 32967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // In case where <Terminate Arc> is started by <Request ARC Termination> 33067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // need to clean up RequestArcInitiationAction. 33167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // TODO: check conditions of power status by calling is_connected api 33267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang // to be added soon. 33367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang removeAction(RequestArcTerminationAction.class); 33467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 33567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang message.getDestination(), message.getSource(), false); 33667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang addAndStartAction(action); 33767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 33867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 339a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private void handleGetCecVersion(HdmiCecMessage message) { 340a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang int version = mCecController.getVersion(); 341a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(), 342a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getSource(), 343a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang version); 344a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand(cecMessage); 345a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 346a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 347a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private void handleGiveDeviceVendorId(HdmiCecMessage message) { 348a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang int vendorId = mCecController.getVendorId(); 349a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 350a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getDestination(), vendorId); 351a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand(cecMessage); 352a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 353a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 354a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private void handleGivePhysicalAddress(HdmiCecMessage message) { 355a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang int physicalAddress = mCecController.getPhysicalAddress(); 356a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang int deviceType = HdmiCec.getTypeFromAddress(message.getDestination()); 357a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 358a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getDestination(), physicalAddress, deviceType); 359a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand(cecMessage); 360a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 361a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 362be9cd8eb3fe64a572f9c7dfc41f04defd46a752dJungshik Jang private void handleGiveOsdName(HdmiCecMessage message) { 363a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // TODO: read device name from settings or property. 364a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang String name = HdmiCec.getDefaultDeviceName(message.getDestination()); 365a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand( 366a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getDestination(), message.getSource(), name); 367a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang if (cecMessage != null) { 368a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand(cecMessage); 369a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } else { 370a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang Slog.w(TAG, "Failed to build <Get Osd Name>:" + name); 371a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 372a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 373a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 374a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang private void handleGetMenuLanguage(HdmiCecMessage message) { 375a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // Only 0 (TV), 14 (specific use) can answer. 376a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang if (message.getDestination() != HdmiCec.ADDR_TV 377a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang && message.getDestination() != HdmiCec.ADDR_SPECIFIC_USE) { 378a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString()); 379a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand( 380a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(), 381a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE, 382a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessageBuilder.ABORT_UNRECOGNIZED_MODE)); 383a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang return; 384a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 385a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 386a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( 387a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang message.getDestination(), 388a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang Locale.getDefault().getISO3Language()); 389a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang // TODO: figure out how to handle failed to get language code. 390a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang if (command != null) { 391a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang sendCecCommand(command); 392a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } else { 393a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString()); 394a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 395a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 39678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 39778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 39878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 39978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 40078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 40178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 40278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 40378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 40478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 40578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 40678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 40778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 40878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 40978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 41078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 41178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 41278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 41378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 41478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 415cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang void addCecDevice(HdmiCecDeviceInfo info) { 416cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCecController.addDeviceInfo(info); 417cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 418cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 419cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // Launch device discovery sequence. 420cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // It starts with clearing the existing device info list. 421cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // Note that it assumes that logical address of all local devices is already allocated. 422cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang void launchDeviceDiscovery() { 423cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // At first, clear all existing device infos. 424cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCecController.clearDeviceInfoList(); 425cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 426cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // TODO: check whether TV is one of local devices. 427cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, HdmiCec.ADDR_TV, 428cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang new DeviceDiscoveryCallback() { 429cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang @Override 430cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { 431cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang for (HdmiCecDeviceInfo info : deviceInfos) { 432cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCecController.addDeviceInfo(info); 433cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 434cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 435cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // Add device info of all local devices. 436cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 437cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCecController.addDeviceInfo(device.getDeviceInfo()); 438cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 439cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 440cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // TODO: start hot-plug detection sequence here. 441cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // addAndStartAction(new HotplugDetectionAction()); 442cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 443cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang }); 444cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang addAndStartAction(action); 445cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 446cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 44778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 44878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 44978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 45078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 45178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 45278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 45378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 45478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 45578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 45678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return mLocalDevices; 45778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 45878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 45978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 46078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 4617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 46278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 4637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 4647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 4657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 4667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 4677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 4687fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 46978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 47078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 47178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 4727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 47378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 4747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 4757fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 4767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 4777fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 4787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 4797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 48078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 48178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 48278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 4837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 48478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 4857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 4867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 4877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 4887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 4897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 4907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 49178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 49278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 49378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 4947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 49578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 4967fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 4977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 4987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 4997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 5007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 50278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 50578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void oneTouchPlay(IHdmiControlCallback callback) { 5067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (hasAction(OneTouchPlayAction.class)) { 5077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "oneTouchPlay already in progress"); 5087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); 5097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 5127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 5137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 5147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 5157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // TODO: Consider the case of multiple TV sets. For now we always direct the command 5187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim // to the primary one. 5197fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim OneTouchPlayAction action = OneTouchPlayAction.create(this, 5207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getLogicalAddress(), 5217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback); 5227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action == null) { 5237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Cannot initiate oneTouchPlay"); 5247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); 5257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim addAndStartAction(action); 52878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 52978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 53078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void queryDisplayStatus(IHdmiControlCallback callback) { 5317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (hasAction(DevicePowerStatusAction.class)) { 5327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "queryDisplayStatus already in progress"); 5337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS); 5347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 5377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 5387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 5397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 5407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim DevicePowerStatusAction action = DevicePowerStatusAction.create(this, 5437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback); 5447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (action == null) { 5457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Cannot initiate queryDisplayStatus"); 5467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_EXCEPTION); 5477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim addAndStartAction(action); 55078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 55278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 55378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 55478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 55578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 55678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 55778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 55878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 55978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 56178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 56278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 56378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 56778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 56878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 56978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 57078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 57178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 57278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 57378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 57678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 5787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 5797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 5807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 5817fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 5827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 5837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 5847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 587