Merge "New "Start dreams" launcher shortcut." into jb-mr1-dev
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index ed1c5b3..2d9dae9 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -688,7 +688,8 @@
                         }
                     } catch (FormatException e) {  }
                 } else if (Arrays.equals(mType, RTD_URI)) {
-                    return parseWktUri().normalizeScheme();
+                    Uri wktUri = parseWktUri();
+                    return (wktUri != null ? wktUri.normalizeScheme() : null);
                 }
                 break;
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index b9a6336..6d27d6e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -68,6 +68,7 @@
 static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
 static const GLsizei gAAVertexStride = sizeof(AAVertex);
 static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
+static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
 static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
 static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7abcc63..a1bb6a2 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1141,6 +1141,10 @@
     mDescription.isAA = true;
 }
 
+void OpenGLRenderer::setupDrawAARect() {
+    mDescription.isAARect = true;
+}
+
 void OpenGLRenderer::setupDrawPoint(float pointSize) {
     mDescription.isPoint = true;
     mDescription.pointSize = pointSize;
@@ -1741,9 +1745,9 @@
 
 /**
  * This function uses a similar approach to that of AA lines in the drawLines() function.
- * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment
- * shader to compute the translucency of the color, determined by whether a given pixel is
- * within that boundary region and how far into the region it is.
+ * We expand the rectangle by a half pixel in screen space on all sides. However, instead of using
+ * a fragment shader to compute the translucency of the color from its position, we simply use a
+ * varying parameter to define how far a given pixel is into the region.
  */
 void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom,
         int color, SkXfermode::Mode mode) {
@@ -1755,10 +1759,8 @@
         Matrix4 *mat = mSnapshot->transform;
         float m00 = mat->data[Matrix4::kScaleX];
         float m01 = mat->data[Matrix4::kSkewY];
-        float m02 = mat->data[2];
         float m10 = mat->data[Matrix4::kSkewX];
         float m11 = mat->data[Matrix4::kScaleX];
-        float m12 = mat->data[6];
         float scaleX = sqrt(m00 * m00 + m01 * m01);
         float scaleY = sqrt(m10 * m10 + m11 * m11);
         inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
@@ -1768,6 +1770,11 @@
     float boundarySizeX = .5 * inverseScaleX;
     float boundarySizeY = .5 * inverseScaleY;
 
+    float innerLeft = left + boundarySizeX;
+    float innerRight = right - boundarySizeX;
+    float innerTop = top + boundarySizeY;
+    float innerBottom = bottom - boundarySizeY;
+
     // Adjust the rect by the AA boundary padding
     left -= boundarySizeX;
     right += boundarySizeX;
@@ -1777,7 +1784,7 @@
     if (!quickReject(left, top, right, bottom)) {
         setupDraw();
         setupDrawNoTexture();
-        setupDrawAALine();
+        setupDrawAARect();
         setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
         setupDrawColorFilter();
         setupDrawShader();
@@ -1788,34 +1795,52 @@
         setupDrawColorFilterUniforms();
         setupDrawShaderIdentityUniforms();
 
-        AAVertex rects[4];
-        AAVertex* aaVertices = &rects[0];
-        void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
-        void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
+        AlphaVertex rects[14];
+        AlphaVertex* aVertices = &rects[0];
+        void* alphaCoords = ((GLbyte*) aVertices) + gVertexAlphaOffset;
 
-        int widthSlot;
-        int lengthSlot;
+        bool force = mCaches.unbindMeshBuffer();
+        mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+                aVertices, gAlphaVertexStride);
+        mCaches.resetTexCoordsVertexPointer();
+        mCaches.unbindIndicesBuffer();
 
-        float width = right - left;
-        float height = bottom - top;
+        int alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
+        glEnableVertexAttribArray(alphaSlot);
+        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
 
-        float boundaryWidthProportion = .5 - ((width != 0) ? (2 * boundarySizeX) / width : 0);
-        float boundaryHeightProportion = .5 - ((height != 0) ? (2 * boundarySizeY) / height : 0);
-        setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
-                boundaryWidthProportion, widthSlot, lengthSlot);
+        // draw left
+        AlphaVertex::set(aVertices++, left, bottom, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+        AlphaVertex::set(aVertices++, left, top, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1);
 
-        int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
-        glUniform1f(boundaryLengthSlot, boundaryHeightProportion);
+        // draw top
+        AlphaVertex::set(aVertices++, right, top, 0);
+        AlphaVertex::set(aVertices++, innerRight, innerTop, 1);
 
-        AAVertex::set(aaVertices++, left, bottom, 1, 1);
-        AAVertex::set(aaVertices++, left, top, 1, 0);
-        AAVertex::set(aaVertices++, right, bottom, 0, 1);
-        AAVertex::set(aaVertices++, right, top, 0, 0);
+        // draw right
+        AlphaVertex::set(aVertices++, right, bottom, 0);
+        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1);
+
+        // draw bottom
+        AlphaVertex::set(aVertices++, left, bottom, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+
+        // draw inner rect (repeating last vertex to create degenerate bridge triangles)
+        // TODO: also consider drawing the inner rect without the blending-forced shader, if
+        // blending is expensive. Note: can't use drawColorRect() since it doesn't use vertex
+        // buffers like below, resulting in slightly different transformed coordinates.
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1);
+        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1);
+        AlphaVertex::set(aVertices++, innerRight, innerTop, 1);
+
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
 
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);
 
-        finishDrawAALine(widthSlot, lengthSlot);
+        glDisableVertexAttribArray(alphaSlot);
     }
 }
 
@@ -1870,10 +1895,8 @@
             Matrix4 *mat = mSnapshot->transform;
             float m00 = mat->data[Matrix4::kScaleX];
             float m01 = mat->data[Matrix4::kSkewY];
-            float m02 = mat->data[2];
             float m10 = mat->data[Matrix4::kSkewX];
             float m11 = mat->data[Matrix4::kScaleX];
-            float m12 = mat->data[6];
 
             float scaleX = sqrtf(m00 * m00 + m01 * m01);
             float scaleY = sqrtf(m10 * m10 + m11 * m11);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4c7cf0a..f2b5f0a 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -434,7 +434,6 @@
      * @param color The rectangle's ARGB color, defined as a packed 32 bits word
      * @param mode The Skia xfermode to use
      * @param ignoreTransform True if the current transform should be ignored
-     * @param ignoreBlending True if the blending is set by the caller
      */
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
@@ -649,6 +648,7 @@
     void setupDrawWithExternalTexture();
     void setupDrawNoTexture();
     void setupDrawAALine();
+    void setupDrawAARect();
     void setupDrawPoint(float pointSize);
     void setupDrawColor(int color);
     void setupDrawColor(int color, int alpha);
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 1818f82..a3bfaa4 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -81,6 +81,8 @@
 
 #define PROGRAM_IS_SIMPLE_GRADIENT 41
 
+#define PROGRAM_IS_AA_RECT_SHIFT 42
+
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
@@ -128,6 +130,7 @@
     bool isBitmapNpot;
 
     bool isAA;
+    bool isAARect;
 
     bool hasGradient;
     Gradient gradientType;
@@ -165,6 +168,7 @@
         hasTextureTransform = false;
 
         isAA = false;
+        isAARect = false;
 
         modulate = false;
 
@@ -260,6 +264,7 @@
         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
         if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
         if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
+        if (isAARect) key |= programid(0x1) << PROGRAM_IS_AA_RECT_SHIFT;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8a9a2ac..0ed8008 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -43,6 +43,8 @@
 const char* gVS_Header_Attributes_AAParameters =
         "attribute float vtxWidth;\n"
         "attribute float vtxLength;\n";
+const char* gVS_Header_Attributes_AARectParameters =
+        "attribute float vtxAlpha;\n";
 const char* gVS_Header_Uniforms_TextureTransform =
         "uniform mat4 mainTextureTransform;\n";
 const char* gVS_Header_Uniforms =
@@ -65,6 +67,8 @@
 const char* gVS_Header_Varyings_IsAA =
         "varying float widthProportion;\n"
         "varying float lengthProportion;\n";
+const char* gVS_Header_Varyings_IsAARect =
+        "varying float alpha;\n";
 const char* gVS_Header_Varyings_HasBitmap =
         "varying highp vec2 outBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_PointHasBitmap =
@@ -112,6 +116,8 @@
 const char* gVS_Main_AA =
         "    widthProportion = vtxWidth;\n"
         "    lengthProportion = vtxLength;\n";
+const char* gVS_Main_AARect =
+        "    alpha = vtxAlpha;\n";
 const char* gVS_Footer =
         "}\n\n";
 
@@ -242,6 +248,8 @@
 const char* gFS_Main_AccountForAA =
         "    fragColor *= (1.0 - smoothstep(boundaryWidth, 0.5, abs(0.5 - widthProportion)))\n"
         "               * (1.0 - smoothstep(boundaryLength, 0.5, abs(0.5 - lengthProportion)));\n";
+const char* gFS_Main_AccountForAARect =
+        "    fragColor *= alpha;\n";
 
 const char* gFS_Main_FetchTexture[2] = {
         // Don't modulate
@@ -439,7 +447,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Attributes_TexCoords);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Attributes_AARectParameters);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Attributes_AAParameters);
     }
     // Uniforms
@@ -460,7 +470,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Varyings_IsAARect);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
@@ -479,7 +491,9 @@
         } else if (description.hasTexture || description.hasExternalTexture) {
             shader.append(gVS_Main_OutTexCoords);
         }
-        if (description.isAA) {
+        if (description.isAARect) {
+            shader.append(gVS_Main_AARect);
+        } else if (description.isAA) {
             shader.append(gVS_Main_AA);
         }
         if (description.hasGradient) {
@@ -521,7 +535,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Varyings_IsAARect);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
@@ -562,7 +578,8 @@
 
     // Optimization for common cases
     if (!description.isAA && !blendFramebuffer &&
-            description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
+            description.colorOp == ProgramDescription::kColorNone &&
+            !description.isPoint && !description.isAARect) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -654,7 +671,9 @@
                 shader.append(gFS_Main_FetchColor);
             }
         }
-        if (description.isAA) {
+        if (description.isAARect) {
+            shader.append(gFS_Main_AccountForAARect);
+        } else if (description.isAA) {
             shader.append(gFS_Main_AccountForAA);
         }
         if (description.hasGradient) {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 0d7b45e..88cf4ac 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1415,7 +1415,8 @@
         long lastModifiedSeconds = file.lastModified() / 1000;
 
         if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
-            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {
+            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) &&
+            !MediaFile.isDrmFileType(fileType)) {
 
             // no need to use the media scanner, but we need to update last modified and file size
             ContentValues values = new ContentValues();
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
index d683af9..c209055 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
@@ -16,5 +16,5 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_selected="true" />
     <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
-    <item android:drawable="@*android:color/transparent"/>
+    <item android:drawable="@drawable/recents_thumbnail_no_press"/>
 </selector>
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml b/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml
new file mode 100644
index 0000000..be07b2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="#00000000" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
index e8cdbc3..7ea2a62d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
@@ -113,6 +113,12 @@
                 canvas.rotate(45);
                 canvas.drawRect(0, 0, 20, 10, p);
                 canvas.restore();
+                canvas.save();
+                canvas.translate(mOffset + 280, yOffset);
+                canvas.scale(0.5f, 8);
+                canvas.rotate(0.5f);
+                canvas.drawRect(0, 0, 80, 5, p);
+                canvas.restore();
                 canvas.restore();
 
                 yOffset += 100;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index b9feb34..805faa6 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -500,6 +500,14 @@
         }
     }
 
+    public boolean setWfdEnable(boolean enable) {
+        return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
+    }
+
+    public boolean setWfdDeviceInfo(String hex) {
+        return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
+    }
+
     /**
      * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
      * P2P connection over STA
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index c86ec8b..117af82 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -107,12 +107,14 @@
     /** Device connection status */
     public int status = UNAVAILABLE;
 
-    /** Detailed device string pattern
+    /** @hide */
+    public WifiP2pWfdInfo wfdInfo;
+
+    /** Detailed device string pattern with WFD info
      * Example:
-     *  P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13
-     *  pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27
-     *  group_capab=0x0
-     *
+     *  P2P-DEVICE-FOUND 00:18:6b:de:a3:6e p2p_dev_addr=00:18:6b:de:a3:6e
+     *  pri_dev_type=1-0050F204-1 name='DWD-300-DEA36E' config_methods=0x188
+     *  dev_capab=0x21 group_capab=0x9
      */
     private static final Pattern detailedDevicePattern = Pattern.compile(
         "((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " +
@@ -273,6 +275,7 @@
         sbuf.append("\n grpcapab: ").append(groupCapability);
         sbuf.append("\n devcapab: ").append(deviceCapability);
         sbuf.append("\n status: ").append(status);
+        sbuf.append("\n wfdInfo: ").append(wfdInfo);
         return sbuf.toString();
     }
 
@@ -292,6 +295,7 @@
             deviceCapability = source.deviceCapability;
             groupCapability = source.groupCapability;
             status = source.status;
+            wfdInfo = source.wfdInfo;
         }
     }
 
@@ -305,6 +309,12 @@
         dest.writeInt(deviceCapability);
         dest.writeInt(groupCapability);
         dest.writeInt(status);
+        if (wfdInfo != null) {
+            dest.writeInt(1);
+            wfdInfo.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** Implement the Parcelable interface */
@@ -320,6 +330,9 @@
                 device.deviceCapability = in.readInt();
                 device.groupCapability = in.readInt();
                 device.status = in.readInt();
+                if (in.readInt() == 1) {
+                    device.wfdInfo = WifiP2pWfdInfo.CREATOR.createFromParcel(in);
+                }
                 return device;
             }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index dce315a..8972b7e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -44,8 +44,8 @@
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("groupFormed: ").append(groupFormed)
-            .append("isGroupOwner: ").append(isGroupOwner)
-            .append("groupOwnerAddress: ").append(groupOwnerAddress);
+            .append(" isGroupOwner: ").append(isGroupOwner)
+            .append(" groupOwnerAddress: ").append(groupOwnerAddress);
         return sbuf.toString();
     }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 96d3a7f..6edc232 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -455,6 +455,13 @@
     /** @hide */
     public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 63;
 
+    /** @hide */
+    public static final int SET_WFD_INFO                            = BASE + 64;
+    /** @hide */
+    public static final int SET_WFD_INFO_FAILED                     = BASE + 65;
+    /** @hide */
+    public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 66;
+
     /**
      * Create a new WifiP2pManager instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -742,6 +749,7 @@
                     case WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED:
                     case WifiP2pManager.SET_DEVICE_NAME_FAILED:
                     case WifiP2pManager.DELETE_PERSISTENT_GROUP_FAILED:
+                    case WifiP2pManager.SET_WFD_INFO_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -762,6 +770,7 @@
                     case WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED:
                     case WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED:
                     case WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED:
+                    case WifiP2pManager.SET_WFD_INFO_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -1297,6 +1306,13 @@
         c.mAsyncChannel.sendMessage(SET_DEVICE_NAME, 0, c.putListener(listener), d);
     }
 
+    /** @hide */
+    public void setWFDInfo(
+            Channel c, WifiP2pWfdInfo wfdInfo,
+            ActionListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
+    }
 
     /**
      * Set dialog listener to over-ride system dialogs on p2p events. This function
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index c34d70e..acb7e52 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -496,6 +496,10 @@
                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
                             WifiP2pManager.BUSY);
                     break;
+                case WifiP2pManager.SET_WFD_INFO:
+                    replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                            WifiP2pManager.BUSY);
+                    break;
                 case WifiP2pManager.REQUEST_PEERS:
                     replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers);
                     break;
@@ -629,6 +633,10 @@
                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
+                case WifiP2pManager.SET_WFD_INFO:
+                    replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
                default:
                     return NOT_HANDLED;
             }
@@ -741,6 +749,7 @@
                     transitionTo(mP2pDisablingState);
                     break;
                 case WifiP2pManager.SET_DEVICE_NAME:
+                {
                     WifiP2pDevice d = (WifiP2pDevice) message.obj;
                     if (d != null && setAndPersistDeviceName(d.deviceName)) {
                         if (DBG) logd("set device name " + d.deviceName);
@@ -750,6 +759,18 @@
                                 WifiP2pManager.ERROR);
                     }
                     break;
+                }
+                case WifiP2pManager.SET_WFD_INFO:
+                {
+                    WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
+                    if (d != null && setWfdInfo(d)) {
+                        replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                                WifiP2pManager.ERROR);
+                    }
+                    break;
+                }
                 case WifiP2pManager.DISCOVER_PEERS:
                     // do not send service discovery request while normal find operation.
                     clearSupplicantServiceRequest();
@@ -2018,6 +2039,27 @@
         return true;
     }
 
+    private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
+        boolean success;
+
+        if (!wfdInfo.isWfdEnabled()) {
+            success = mWifiNative.setWfdEnable(false);
+        } else {
+            success =
+                mWifiNative.setWfdEnable(true)
+                && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
+        }
+
+        if (!success) {
+            loge("Failed to set wfd properties");
+            return false;
+        }
+
+        mThisDevice.wfdInfo = wfdInfo;
+        sendThisDeviceChangedBroadcast();
+        return true;
+    }
+
     private void initializeP2pSettings() {
         mWifiNative.setPersistentReconnect(true);
         mThisDevice.deviceName = getPersistedDeviceName();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
new file mode 100644
index 0000000..9dd3e4a
--- /dev/null
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.p2p;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * A class representing Wifi Display information for a device
+ * @hide
+ */
+public class WifiP2pWfdInfo implements Parcelable {
+
+    private static final String TAG = "WifiP2pWfdInfo";
+
+    private boolean mWfdEnabled;
+
+    private int mDeviceInfo;
+
+    public static final int WFD_SOURCE              = 0;
+    public static final int PRIMARY_SINK            = 1;
+    public static final int SECONDARY_SINK          = 2;
+    public static final int SOURCE_OR_PRIMARY_SINK  = 3;
+
+    /* Device information bitmap */
+    /** One of {@link #WFD_SOURCE}, {@link #PRIMARY_SINK}, {@link #SECONDARY_SINK}
+     * or {@link #SOURCE_OR_PRIMARY_SINK}
+     */
+    private static final int DEVICE_TYPE                            = 0x3;
+    private static final int COUPLED_SINK_SUPPORT_AT_SOURCE         = 0x4;
+    private static final int COUPLED_SINK_SUPPORT_AT_SINK           = 0x8;
+    private static final int SESSION_AVAILABLE                      = 0x30;
+    private static final int SESSION_AVAILABLE_BIT1                 = 0x10;
+    private static final int SESSION_AVAILABLE_BIT2                 = 0x20;
+
+    private int mCtrlPort;
+
+    private int mMaxThroughput;
+
+    public WifiP2pWfdInfo() {
+    }
+
+    public boolean isWfdEnabled() {
+        return mWfdEnabled;
+    }
+
+    public void setWfdEnabled(boolean enabled) {
+        mWfdEnabled = enabled;
+    }
+
+    public int getDeviceType() {
+        return (mDeviceInfo & DEVICE_TYPE);
+    }
+
+    public boolean setDeviceType(int deviceType) {
+        if (deviceType >= WFD_SOURCE && deviceType <= SOURCE_OR_PRIMARY_SINK) {
+            mDeviceInfo |= deviceType;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isCoupledSinkSupportedAtSource() {
+        return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
+    }
+
+    public void setCoupledSinkSupportAtSource(boolean enabled) {
+        if (enabled ) {
+            mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
+        } else {
+            mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
+        }
+    }
+
+    public boolean isCoupledSinkSupportedAtSink() {
+        return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
+    }
+
+    public void setCoupledSinkSupportAtSink(boolean enabled) {
+        if (enabled ) {
+            mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
+        } else {
+            mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
+        }
+    }
+
+    public boolean isSessionAvailable() {
+        return (mDeviceInfo & SESSION_AVAILABLE) != 0;
+    }
+
+    public void setSessionAvailable(boolean enabled) {
+        if (enabled) {
+            mDeviceInfo |= SESSION_AVAILABLE_BIT1;
+            mDeviceInfo &= ~SESSION_AVAILABLE_BIT2;
+        } else {
+            mDeviceInfo &= ~SESSION_AVAILABLE;
+        }
+    }
+
+    public int getControlPort() {
+        return mCtrlPort;
+    }
+
+    public void setControlPort(int port) {
+        mCtrlPort = port;
+    }
+
+    public void setMaxThroughput(int maxThroughput) {
+        mMaxThroughput = maxThroughput;
+    }
+
+    public int getMaxThroughput() {
+        return mMaxThroughput;
+    }
+
+    public String getDeviceInfoHex() {
+        return String.format("%04x%04x%04x%04x", 6, mDeviceInfo, mCtrlPort, mMaxThroughput);
+    }
+
+    public String toString() {
+        StringBuffer sbuf = new StringBuffer();
+        sbuf.append("WFD enabled: ").append(mWfdEnabled);
+        sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo);
+        sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort);
+        sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput);
+        return sbuf.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** copy constructor */
+    public WifiP2pWfdInfo(WifiP2pWfdInfo source) {
+        if (source != null) {
+            mDeviceInfo = source.mDeviceInfo;
+            mCtrlPort = source.mCtrlPort;
+            mMaxThroughput = source.mMaxThroughput;
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mWfdEnabled ? 1 : 0);
+        dest.writeInt(mDeviceInfo);
+        dest.writeInt(mCtrlPort);
+        dest.writeInt(mMaxThroughput);
+    }
+
+    public void readFromParcel(Parcel in) {
+        mWfdEnabled = (in.readInt() == 1);
+        mDeviceInfo = in.readInt();
+        mCtrlPort = in.readInt();
+        mMaxThroughput = in.readInt();
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<WifiP2pWfdInfo> CREATOR =
+        new Creator<WifiP2pWfdInfo>() {
+            public WifiP2pWfdInfo createFromParcel(Parcel in) {
+                WifiP2pWfdInfo device = new WifiP2pWfdInfo();
+                device.readFromParcel(in);
+                return device;
+            }
+
+            public WifiP2pWfdInfo[] newArray(int size) {
+                return new WifiP2pWfdInfo[size];
+            }
+        };
+}