HDMI plug intent and associated information

Read HDMI device information from audio ports and add it as
 extras in the connection intent.
Document the new extras in the connection intent.
Make Intent.ACTION_HDMI_AUDIO_PLUG public.

Bug 10549017

Change-Id: I6236b5363f00c433e443195fae8c43af2fc834f7
diff --git a/api/current.txt b/api/current.txt
index 652bfe2..e8d1369 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7702,6 +7702,7 @@
     field public static final java.lang.String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
     field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
     field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
+    field public static final java.lang.String ACTION_HDMI_AUDIO_PLUG = "android.intent.action.HDMI_AUDIO_PLUG";
     field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
     field public static final java.lang.String ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED";
     field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 04a06af..974ff13 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2279,15 +2279,20 @@
             "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG";
 
     /**
-     * Broadcast Action: A HMDI cable was plugged or unplugged
+     * Broadcast Action: A sticky broadcast indicating an HMDI cable was plugged or unplugged
      *
      * <p>The intent will have the following extra values:
      * <ul>
      *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
      *   <li><em>name</em> - HDMI cable, human readable string </li>
+     *   <li><em>maxChannelCount</em> - the maximum number of output channels supported by the
+     *       connected HDMI device, only available when <i>state</i> is 1.</li>
+     *   <li><em>encodings</em> - an array of formats supported by the connected HDMI device,
+     *       only available when <i>state</i> is 1. Encoding values are defined in
+     *       {@link android.media.AudioFormat} (for instance see
+     *       {@link android.media.AudioFormat#ENCODING_PCM_16BIT}). Use
+     *       {@link #getIntArrayExtra(String)} to retrieve the encoding values.</li>
      * </ul>
-     * </ul>
-     * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_HDMI_AUDIO_PLUG =
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index fb7f0c6..c6489a6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4389,7 +4389,7 @@
             intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
         } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
             connType = AudioRoutesInfo.MAIN_HDMI;
-            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
+            configureHdmiPlugIntent(intent, state);
         }
 
         synchronized (mCurAudioRoutes) {
@@ -4471,6 +4471,49 @@
         }
     }
 
+    private void configureHdmiPlugIntent(Intent intent, int state) {
+        intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
+        if (state == 1) {
+            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
+            int[] portGeneration = new int[1];
+            int status = AudioSystem.listAudioPorts(ports, portGeneration);
+            if (status == AudioManager.SUCCESS) {
+                for (AudioPort port : ports) {
+                    if (port instanceof AudioDevicePort) {
+                        final AudioDevicePort devicePort = (AudioDevicePort) port;
+                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI) {
+                            // format the list of supported encodings
+                            int[] formats = devicePort.formats();
+                            if (formats.length > 0) {
+                                ArrayList<Integer> encodingList = new ArrayList(1);
+                                for (int format : formats) {
+                                    // a format in the list can be 0, skip it
+                                    if (format != AudioFormat.ENCODING_INVALID) {
+                                        encodingList.add(format);
+                                    }
+                                }
+                                int[] encodingArray = new int[encodingList.size()];
+                                for (int i = 0 ; i < encodingArray.length ; i++) {
+                                    encodingArray[i] = encodingList.get(i);
+                                }
+                                intent.putExtra("encodings", encodingArray);
+                            }
+                            // find the maximum supported number of channels
+                            int maxChannels = 0;
+                            for (int mask : devicePort.channelMasks()) {
+                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
+                                if (channelCount > maxChannels) {
+                                    maxChannels = channelCount;
+                                }
+                            }
+                            intent.putExtra("maxChannelCount", maxChannels);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /* cache of the address of the last dock the device was connected to */
     private String mDockAddress;