Home | History | Annotate | Download | only in hdmi
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware.hdmi;
     18 
     19 import android.annotation.Nullable;
     20 import android.annotation.RequiresFeature;
     21 import android.annotation.RequiresPermission;
     22 import android.annotation.SdkConstant;
     23 import android.annotation.SdkConstant.SdkConstantType;
     24 import android.annotation.SuppressLint;
     25 import android.content.Context;
     26 import android.content.pm.PackageManager;
     27 import android.annotation.SystemApi;
     28 import android.annotation.SystemService;
     29 import android.os.RemoteException;
     30 import android.util.ArrayMap;
     31 import android.util.Log;
     32 
     33 /**
     34  * The {@link HdmiControlManager} class is used to send HDMI control messages
     35  * to attached CEC devices.
     36  *
     37  * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
     38  * hosted in the system. {@link #getTvClient()}, for instance will return an
     39  * {@link HdmiTvClient} object if the system is configured to host one. Android system
     40  * can host more than one logical CEC devices. If multiple types are configured they
     41  * all work as if they were independent logical devices running in the system.
     42  *
     43  * @hide
     44  */
     45 @SystemApi
     46 @SystemService(Context.HDMI_CONTROL_SERVICE)
     47 @RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
     48 public final class HdmiControlManager {
     49     private static final String TAG = "HdmiControlManager";
     50 
     51     @Nullable private final IHdmiControlService mService;
     52 
     53     /**
     54      * Broadcast Action: Display OSD message.
     55      * <p>Send when the service has a message to display on screen for events
     56      * that need user's attention such as ARC status change.
     57      * <p>Always contains the extra fields {@link #EXTRA_MESSAGE_ID}.
     58      * <p>Requires {@link android.Manifest.permission#HDMI_CEC} to receive.
     59      */
     60     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     61     public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
     62 
     63     // --- Messages for ACTION_OSD_MESSAGE ---
     64     /**
     65      * Message that ARC enabled device is connected to invalid port (non-ARC port).
     66      */
     67     public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1;
     68 
     69     /**
     70      * Message used by TV to receive volume status from Audio Receiver. It should check volume value
     71      * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRA_PARAM1}. If the
     72      * value is in range of [0,100], it is current volume of Audio Receiver. And there is another
     73      * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute.
     74      */
     75     public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2;
     76 
     77     /**
     78      * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of
     79      * the message to display on screen.
     80      */
     81     public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
     82     /**
     83      * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value
     84      * of the message.
     85      */
     86     public static final String EXTRA_MESSAGE_EXTRA_PARAM1 =
     87             "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
     88 
     89     /**
     90      * Volume value for mute state.
     91      */
     92     public static final int AVR_VOLUME_MUTED = 101;
     93 
     94     public static final int POWER_STATUS_UNKNOWN = -1;
     95     public static final int POWER_STATUS_ON = 0;
     96     public static final int POWER_STATUS_STANDBY = 1;
     97     public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
     98     public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
     99 
    100     public static final int RESULT_SUCCESS = 0;
    101     public static final int RESULT_TIMEOUT = 1;
    102     public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
    103     public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
    104 
    105     @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4;
    106     public static final int RESULT_EXCEPTION = 5;
    107     public static final int RESULT_INCORRECT_MODE = 6;
    108     public static final int RESULT_COMMUNICATION_FAILED = 7;
    109 
    110     public static final int DEVICE_EVENT_ADD_DEVICE = 1;
    111     public static final int DEVICE_EVENT_REMOVE_DEVICE = 2;
    112     public static final int DEVICE_EVENT_UPDATE_DEVICE = 3;
    113 
    114     // --- One Touch Recording success result
    115     /** Recording currently selected source. Indicates the status of a recording. */
    116     public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01;
    117     /** Recording Digital Service. Indicates the status of a recording. */
    118     public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02;
    119     /** Recording Analogue Service. Indicates the status of a recording. */
    120     public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03;
    121     /** Recording External input. Indicates the status of a recording. */
    122     public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04;
    123 
    124     // --- One Touch Record failure result
    125     /** No recording  unable to record Digital Service. No suitable tuner. */
    126     public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05;
    127     /** No recording  unable to record Analogue Service. No suitable tuner. */
    128     public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06;
    129     /**
    130      * No recording  unable to select required service. as suitable tuner, but the requested
    131      * parameters are invalid or out of range for that tuner.
    132      */
    133     public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07;
    134     /** No recording  invalid External plug number */
    135     public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09;
    136     /** No recording  invalid External Physical Address */
    137     public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A;
    138     /** No recording  CA system not supported */
    139     public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B;
    140     /** No Recording  No or Insufficient CA Entitlements */
    141     public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C;
    142     /** No recording  Not allowed to copy source. Source is copy never. */
    143     public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D;
    144     /** No recording  No further copies allowed */
    145     public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E;
    146     /** No recording  No media */
    147     public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10;
    148     /** No recording  playing */
    149     public static final int ONE_TOUCH_RECORD_PLAYING = 0x11;
    150     /** No recording  already recording */
    151     public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12;
    152     /** No recording  media protected */
    153     public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13;
    154     /** No recording  no source signal */
    155     public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14;
    156     /** No recording  media problem */
    157     public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15;
    158     /** No recording  not enough space available */
    159     public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16;
    160     /** No recording  Parental Lock On */
    161     public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17;
    162     /** Recording terminated normally */
    163     public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A;
    164     /** Recording has already terminated */
    165     public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B;
    166     /** No recording  other reason */
    167     public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F;
    168     // From here extra message for recording that is not mentioned in CEC spec
    169     /** No recording. Previous recording request in progress. */
    170     public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30;
    171     /** No recording. Please check recorder and connection. */
    172     public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31;
    173     /** Cannot record currently displayed source. */
    174     public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32;
    175     /** CEC is disabled. */
    176     public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33;
    177 
    178     // --- Types for timer recording
    179     /** Timer recording type for digital service source. */
    180     public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
    181     /** Timer recording type for analogue service source. */
    182     public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
    183     /** Timer recording type for external source. */
    184     public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
    185 
    186     // --- Timer Status Data
    187     /** [Timer Status Data/Media Info] - Media present and not protected. */
    188     public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0x0;
    189     /** [Timer Status Data/Media Info] - Media present, but protected. */
    190     public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 0x1;
    191     /** [Timer Status Data/Media Info] - Media not present. */
    192     public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 0x2;
    193 
    194     /** [Timer Status Data/Programmed Info] - Enough space available for recording. */
    195     public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 0x8;
    196     /** [Timer Status Data/Programmed Info] - Not enough space available for recording. */
    197     public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 0x9;
    198     /** [Timer Status Data/Programmed Info] - Might not enough space available for recording. */
    199     public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 0xB;
    200     /** [Timer Status Data/Programmed Info] - No media info available. */
    201     public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 0xA;
    202 
    203     /** [Timer Status Data/Not Programmed Error Info] - No free timer available. */
    204     public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 0x1;
    205     /** [Timer Status Data/Not Programmed Error Info] - Date out of range. */
    206     public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 0x2;
    207     /** [Timer Status Data/Not Programmed Error Info] - Recording Sequence error. */
    208     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 0x3;
    209     /** [Timer Status Data/Not Programmed Error Info] - Invalid External Plug Number. */
    210     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 0x4;
    211     /** [Timer Status Data/Not Programmed Error Info] - Invalid External Physical Address. */
    212     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 0x5;
    213     /** [Timer Status Data/Not Programmed Error Info] - CA system not supported. */
    214     public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 0x6;
    215     /** [Timer Status Data/Not Programmed Error Info] - No or insufficient CA Entitlements. */
    216     public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 0x7;
    217     /** [Timer Status Data/Not Programmed Error Info] - Does not support resolution. */
    218     public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 0x8;
    219     /** [Timer Status Data/Not Programmed Error Info] - Parental Lock On. */
    220     public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON= 0x9;
    221     /** [Timer Status Data/Not Programmed Error Info] - Clock Failure. */
    222     public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 0xA;
    223     /** [Timer Status Data/Not Programmed Error Info] - Duplicate: already programmed. */
    224     public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 0xE;
    225 
    226     // --- Extra result value for timer recording.
    227     /** No extra error. */
    228     public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0x00;
    229     /** No timer recording - check recorder and connection. */
    230     public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01;
    231     /** No timer recording - cannot record selected source. */
    232     public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02;
    233     /** CEC is disabled. */
    234     public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x03;
    235 
    236     // -- Timer cleared status data code used for result of onClearTimerRecordingResult.
    237     /** Timer not cleared  recording. */
    238     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0x00;
    239     /** Timer not cleared  no matching. */
    240     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 0x01;
    241     /** Timer not cleared  no info available. */
    242     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 0x02;
    243     /** Timer cleared. */
    244     public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 0x80;
    245     /** Clear timer error - check recorder and connection. */
    246     public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 0xA0;
    247     /** Clear timer error - cannot clear timer for selected source. */
    248     public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 0xA1;
    249     /** Clear timer error - CEC is disabled. */
    250     public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
    251 
    252     /** The HdmiControlService is started. */
    253     public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
    254     /** The state of HdmiControlService is changed by changing of settings. */
    255     public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
    256     /** The HdmiControlService is enabled to wake up. */
    257     public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
    258     /** The HdmiControlService will be disabled to standby. */
    259     public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
    260 
    261     // True if we have a logical device of type playback hosted in the system.
    262     private final boolean mHasPlaybackDevice;
    263     // True if we have a logical device of type TV hosted in the system.
    264     private final boolean mHasTvDevice;
    265 
    266     /**
    267      * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService,
    268      * which is a system private class. The right way to create an instance of this class is
    269      * using the factory Context.getSystemService.
    270      */
    271     public HdmiControlManager(IHdmiControlService service) {
    272         mService = service;
    273         int[] types = null;
    274         if (mService != null) {
    275             try {
    276                 types = mService.getSupportedTypes();
    277             } catch (RemoteException e) {
    278                 throw e.rethrowFromSystemServer();
    279             }
    280         }
    281         mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
    282         mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
    283     }
    284 
    285     private static boolean hasDeviceType(int[] types, int type) {
    286         if (types == null) {
    287             return false;
    288         }
    289         for (int t : types) {
    290             if (t == type) {
    291                 return true;
    292             }
    293         }
    294         return false;
    295     }
    296 
    297     /**
    298      * Gets an object that represents an HDMI-CEC logical device of a specified type.
    299      *
    300      * @param type CEC device type
    301      * @return {@link HdmiClient} instance. {@code null} on failure.
    302      * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
    303      * See {@link HdmiDeviceInfo#DEVICE_TV}
    304      */
    305     @Nullable
    306     @SuppressLint("Doclava125")
    307     public HdmiClient getClient(int type) {
    308         if (mService == null) {
    309             return null;
    310         }
    311         switch (type) {
    312             case HdmiDeviceInfo.DEVICE_TV:
    313                 return mHasTvDevice ? new HdmiTvClient(mService) : null;
    314             case HdmiDeviceInfo.DEVICE_PLAYBACK:
    315                 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
    316             default:
    317                 return null;
    318         }
    319     }
    320 
    321     /**
    322      * Gets an object that represents an HDMI-CEC logical device of type playback on the system.
    323      *
    324      * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
    325      * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
    326      * system if the system is configured to host more than one type of HDMI-CEC logical devices.
    327      *
    328      * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
    329      */
    330     @Nullable
    331     @SuppressLint("Doclava125")
    332     public HdmiPlaybackClient getPlaybackClient() {
    333         return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
    334     }
    335 
    336     /**
    337      * Gets an object that represents an HDMI-CEC logical device of type TV on the system.
    338      *
    339      * <p>Used to send HDMI control messages to other devices and manage them through
    340      * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
    341      * system if the system is configured to host more than one type of HDMI-CEC logical devices.
    342      *
    343      * @return {@link HdmiTvClient} instance. {@code null} on failure.
    344      */
    345     @Nullable
    346     @SuppressLint("Doclava125")
    347     public HdmiTvClient getTvClient() {
    348         return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
    349     }
    350 
    351     /**
    352      * Controls standby mode of the system. It will also try to turn on/off the connected devices if
    353      * necessary.
    354      *
    355      * @param isStandbyModeOn target status of the system's standby mode
    356      */
    357     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
    358     public void setStandbyMode(boolean isStandbyModeOn) {
    359         try {
    360             mService.setStandbyMode(isStandbyModeOn);
    361         } catch (RemoteException e) {
    362             throw e.rethrowFromSystemServer();
    363         }
    364     }
    365 
    366     /**
    367      * Listener used to get hotplug event from HDMI port.
    368      */
    369     public interface HotplugEventListener {
    370         void onReceived(HdmiHotplugEvent event);
    371     }
    372 
    373     private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener>
    374             mHotplugEventListeners = new ArrayMap<>();
    375 
    376     /**
    377      * Listener used to get vendor-specific commands.
    378      */
    379     public interface VendorCommandListener {
    380         /**
    381          * Called when a vendor command is received.
    382          *
    383          * @param srcAddress source logical address
    384          * @param destAddress destination logical address
    385          * @param params vendor-specific parameters
    386          * @param hasVendorId {@code true} if the command is &lt;Vendor Command
    387          *        With ID&gt;. The first 3 bytes of params is vendor id.
    388          */
    389         void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
    390 
    391         /**
    392          * The callback is called:
    393          * <ul>
    394          *     <li> before HdmiControlService is disabled.
    395          *     <li> after HdmiControlService is enabled and the local address is assigned.
    396          * </ul>
    397          * The client shouldn't hold the thread too long since this is a blocking call.
    398          *
    399          * @param enabled {@code true} if HdmiControlService is enabled.
    400          * @param reason the reason code why the state of HdmiControlService is changed.
    401          * @see #CONTROL_STATE_CHANGED_REASON_START
    402          * @see #CONTROL_STATE_CHANGED_REASON_SETTING
    403          * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
    404          * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
    405          */
    406         void onControlStateChanged(boolean enabled, int reason);
    407     }
    408 
    409     /**
    410      * Adds a listener to get informed of {@link HdmiHotplugEvent}.
    411      *
    412      * <p>To stop getting the notification,
    413      * use {@link #removeHotplugEventListener(HotplugEventListener)}.
    414      *
    415      * @param listener {@link HotplugEventListener} instance
    416      * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
    417      */
    418     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
    419     public void addHotplugEventListener(HotplugEventListener listener) {
    420         if (mService == null) {
    421             Log.e(TAG, "HdmiControlService is not available");
    422             return;
    423         }
    424         if (mHotplugEventListeners.containsKey(listener)) {
    425             Log.e(TAG, "listener is already registered");
    426             return;
    427         }
    428         IHdmiHotplugEventListener wrappedListener = getHotplugEventListenerWrapper(listener);
    429         mHotplugEventListeners.put(listener, wrappedListener);
    430         try {
    431             mService.addHotplugEventListener(wrappedListener);
    432         } catch (RemoteException e) {
    433             throw e.rethrowFromSystemServer();
    434         }
    435     }
    436 
    437     /**
    438      * Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
    439      *
    440      * @param listener {@link HotplugEventListener} instance to be removed
    441      */
    442     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
    443     public void removeHotplugEventListener(HotplugEventListener listener) {
    444         if (mService == null) {
    445             Log.e(TAG, "HdmiControlService is not available");
    446             return;
    447         }
    448         IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener);
    449         if (wrappedListener == null) {
    450             Log.e(TAG, "tried to remove not-registered listener");
    451             return;
    452         }
    453         try {
    454             mService.removeHotplugEventListener(wrappedListener);
    455         } catch (RemoteException e) {
    456             throw e.rethrowFromSystemServer();
    457         }
    458     }
    459 
    460     private IHdmiHotplugEventListener getHotplugEventListenerWrapper(
    461             final HotplugEventListener listener) {
    462         return new IHdmiHotplugEventListener.Stub() {
    463             @Override
    464             public void onReceived(HdmiHotplugEvent event) {
    465                 listener.onReceived(event);;
    466             }
    467         };
    468     }
    469 }
    470