Merge "Convert from SurfaceTexture to Surface"
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 5f2d642..ff5a467 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -378,12 +378,16 @@
      * An index is associated to each block (which will be used by display lists),
      * this class simply invalidates the index of blocks overlapping a modification.
      *
+     * This method is package private and not private so that it can be tested.
+     *
      * @param startLine the first line of the range of modified lines
      * @param endLine the last line of the range, possibly equal to startLine, lower
      * than getLineCount()
      * @param newLineCount the number of lines that will replace the range, possibly 0
+     *
+     * @hide
      */
-    private void updateBlocks(int startLine, int endLine, int newLineCount) {
+    void updateBlocks(int startLine, int endLine, int newLineCount) {
         int firstBlock = -1;
         int lastBlock = -1;
         for (int i = 0; i < mNumberOfBlocks; i++) {
@@ -466,6 +470,18 @@
     }
 
     /**
+     * This package private method is used for test purposes only
+     * @hide
+     */
+    void setBlocksDataForTest(int[] blockEnds, int[] blockIndices, int numberOfBlocks) {
+        mBlockEnds = new int[blockEnds.length];
+        mBlockIndices = new int[blockIndices.length];
+        System.arraycopy(blockEnds, 0, mBlockEnds, 0, blockEnds.length);
+        System.arraycopy(blockIndices, 0, mBlockIndices, 0, blockIndices.length);
+        mNumberOfBlocks = numberOfBlocks;
+    }
+
+    /**
      * @hide
      */
     public int[] getBlockEnds() {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 0e96742..5b0433e 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -214,49 +214,6 @@
     
     private static native void nSetViewport(int renderer, int width, int height);
 
-    /**
-     * Preserves the back buffer of the current surface after a buffer swap.
-     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
-     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
-     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
-     * 
-     * @return True if the swap behavior was successfully changed,
-     *         false otherwise.
-     * 
-     * @hide
-     */
-    public static boolean preserveBackBuffer() {
-        return nPreserveBackBuffer();
-    }
-
-    private static native boolean nPreserveBackBuffer();    
-
-    /**
-     * Indicates whether the current surface preserves its back buffer
-     * after a buffer swap.
-     * 
-     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
-     *         false otherwise
-     *         
-     * @hide
-     */
-    public static boolean isBackBufferPreserved() {
-        return nIsBackBufferPreserved();
-    }
-
-    private static native boolean nIsBackBufferPreserved();
-
-    /**
-     * Disables v-sync. For performance testing only.
-     * 
-     * @hide
-     */
-    public static void disableVsync() {
-        nDisableVsync();
-    }
-
-    private static native void nDisableVsync();
-
     @Override
     public void onPreDraw(Rect dirty) {
         if (dirty != null) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d40043f..81c7ebf 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -282,6 +282,43 @@
     private static native void nBeginFrame();
 
     /**
+     * Preserves the back buffer of the current surface after a buffer swap.
+     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
+     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
+     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
+     *
+     * @return True if the swap behavior was successfully changed,
+     *         false otherwise.
+     */
+    static boolean preserveBackBuffer() {
+        return nPreserveBackBuffer();
+    }
+
+    private static native boolean nPreserveBackBuffer();
+
+    /**
+     * Indicates whether the current surface preserves its back buffer
+     * after a buffer swap.
+     *
+     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
+     *         false otherwise
+     */
+    static boolean isBackBufferPreserved() {
+        return nIsBackBufferPreserved();
+    }
+
+    private static native boolean nIsBackBufferPreserved();
+
+    /**
+     * Disables v-sync. For performance testing only.
+     */
+    static void disableVsync() {
+        nDisableVsync();
+    }
+
+    private static native void nDisableVsync();
+
+    /**
      * Interface used to receive callbacks whenever a view is drawn by
      * a hardware renderer instance.
      */
@@ -777,7 +814,7 @@
             // If mDirtyRegions is set, this means we have an EGL configuration
             // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
             if (sDirtyRegions) {
-                if (!(mDirtyRegionsEnabled = GLES20Canvas.preserveBackBuffer())) {
+                if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
                     Log.w(LOG_TAG, "Backbuffer cannot be preserved");
                 }
             } else if (sDirtyRegionsRequested) {
@@ -787,7 +824,7 @@
                 // want to set mDirtyRegions. We try to do this only if dirty
                 // regions were initially requested as part of the device
                 // configuration (see RENDER_DIRTY_REGIONS)
-                mDirtyRegionsEnabled = GLES20Canvas.isBackBufferPreserved();
+                mDirtyRegionsEnabled = isBackBufferPreserved();
             }
         }
 
@@ -926,7 +963,6 @@
                     }
 
                     beginFrame();
-
                     onPreDraw(dirty);
 
                     HardwareCanvas canvas = mCanvas;
@@ -1203,7 +1239,7 @@
         void setup(int width, int height) {
             super.setup(width, height);
             if (mVsyncDisabled) {
-                GLES20Canvas.disableVsync();
+                disableVsync();
             }
         }
 
@@ -1247,7 +1283,7 @@
                 }
             }
         }
-        
+
         @Override
         void destroyHardwareResources(View view) {
             if (view != null) {
@@ -1265,7 +1301,7 @@
                 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
             }
         }
-        
+
         private static void destroyResources(View view) {
             view.destroyHardwareResources();
 
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index efeba5c..a7abbfa 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -341,6 +341,8 @@
     mHebrewBoldTypeface = NULL;
     mBengaliTypeface = NULL;
     mThaiTypeface = NULL;
+    mDevanagariTypeface = NULL;
+    mTamilTypeface = NULL;
 
     mFontRec.klass = &harfbuzzSkiaClass;
     mFontRec.userData = 0;
@@ -383,6 +385,8 @@
     SkSafeUnref(mHebrewBoldTypeface);
     SkSafeUnref(mBengaliTypeface);
     SkSafeUnref(mThaiTypeface);
+    SkSafeUnref(mDevanagariTypeface);
+    SkSafeUnref(mTamilTypeface);
     deleteShaperItemGlyphArrays();
 }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index baf296d..b472eef 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -62,9 +62,9 @@
  */
 #ifdef USE_OPENGL_RENDERER
 
-///////////////////////////////////////////////////////////////////////////////
+// ----------------------------------------------------------------------------
 // Defines
-///////////////////////////////////////////////////////////////////////////////
+// ----------------------------------------------------------------------------
 
 // Debug
 #define DEBUG_RENDERER 0
@@ -87,52 +87,9 @@
 } gRectClassInfo;
 
 // ----------------------------------------------------------------------------
-// Misc
+// Caching
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_GLES20Canvas_preserveBackBuffer(JNIEnv* env, jobject clazz) {
-    EGLDisplay display = eglGetCurrentDisplay();
-    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
-
-    eglGetError();
-    eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
-
-    EGLint error = eglGetError();
-    if (error != EGL_SUCCESS) {
-        RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error);
-    }
-
-    return error == EGL_SUCCESS;
-}
-
-static jboolean android_view_GLES20Canvas_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
-    EGLDisplay display = eglGetCurrentDisplay();
-    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
-    EGLint value;
-
-    eglGetError();
-    eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &value);
-
-    EGLint error = eglGetError();
-    if (error != EGL_SUCCESS) {
-        RENDERER_LOGD("Could not query buffer preserved swap behavior (%x)", error);
-    }
-
-    return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
-}
-
-static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) {
-    EGLDisplay display = eglGetCurrentDisplay();
-
-    eglGetError();
-    eglSwapInterval(display, 0);
-
-    EGLint error = eglGetError();
-    if (error != EGL_SUCCESS) {
-        RENDERER_LOGD("Could not disable v-sync (%x)", error);
-    }
-}
-
 static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz,
         Caches::FlushMode mode) {
     if (Caches::hasInstance()) {
@@ -853,9 +810,6 @@
     { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
 
 #ifdef USE_OPENGL_RENDERER
-    { "nIsBackBufferPreserved", "()Z",         (void*) android_view_GLES20Canvas_isBackBufferPreserved },
-    { "nPreserveBackBuffer",    "()Z",         (void*) android_view_GLES20Canvas_preserveBackBuffer },
-    { "nDisableVsync",          "()V",         (void*) android_view_GLES20Canvas_disableVsync },
     { "nFlushCaches",           "(I)V",        (void*) android_view_GLES20Canvas_flushCaches },
     { "nInitCaches",            "()V",         (void*) android_view_GLES20Canvas_initCaches },
     { "nTerminateCaches",       "()V",         (void*) android_view_GLES20Canvas_terminateCaches },
@@ -869,8 +823,7 @@
 
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
-    { "nCallDrawGLFunction", "(II)I",
-            (void*) android_view_GLES20Canvas_callDrawGLFunction },
+    { "nCallDrawGLFunction", "(II)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
 
     { "nSave",              "(II)I",           (void*) android_view_GLES20Canvas_save },
     { "nRestore",           "(I)V",            (void*) android_view_GLES20Canvas_restore },
@@ -962,7 +915,7 @@
     { "nResizeLayer",            "(III[I)V" ,  (void*) android_view_GLES20Canvas_resizeLayer },
     { "nCreateTextureLayer",     "(Z[I)I",     (void*) android_view_GLES20Canvas_createTextureLayer },
     { "nUpdateTextureLayer",     "(IIIZLandroid/graphics/SurfaceTexture;)V",
-                                               (void*) android_view_GLES20Canvas_updateTextureLayer },
+            (void*) android_view_GLES20Canvas_updateTextureLayer },
     { "nUpdateRenderLayer",      "(IIIIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index cdcde51..4b62169 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -20,14 +20,95 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
-#include <EGL/egl_cache.h>
-
-EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+#ifdef USE_OPENGL_RENDERER
+    #include <EGL/egl_cache.h>
+    EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+#endif
 
 namespace android {
 
+/**
+ * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
+ *       devices. This means all the logic must be compiled only when the
+ *       preprocessor variable USE_OPENGL_RENDERER is defined.
+ */
+#ifdef USE_OPENGL_RENDERER
+
 // ----------------------------------------------------------------------------
-// Misc
+// Defines
+// ----------------------------------------------------------------------------
+
+// Debug
+#define DEBUG_RENDERER 0
+
+// Debug
+#if DEBUG_RENDERER
+    #define RENDERER_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+    #define RENDERER_LOGD(...)
+#endif
+
+// ----------------------------------------------------------------------------
+// Surface and display management
+// ----------------------------------------------------------------------------
+
+static jboolean android_view_HardwareRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
+    EGLDisplay display = eglGetCurrentDisplay();
+    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
+
+    eglGetError();
+    eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+
+    EGLint error = eglGetError();
+    if (error != EGL_SUCCESS) {
+        RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error);
+    }
+
+    return error == EGL_SUCCESS;
+}
+
+static jboolean android_view_HardwareRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
+    EGLDisplay display = eglGetCurrentDisplay();
+    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
+    EGLint value;
+
+    eglGetError();
+    eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &value);
+
+    EGLint error = eglGetError();
+    if (error != EGL_SUCCESS) {
+        RENDERER_LOGD("Could not query buffer preserved swap behavior (%x)", error);
+    }
+
+    return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
+}
+
+static void android_view_HardwareRenderer_disableVsync(JNIEnv* env, jobject clazz) {
+    EGLDisplay display = eglGetCurrentDisplay();
+
+    eglGetError();
+    eglSwapInterval(display, 0);
+
+    EGLint error = eglGetError();
+    if (error != EGL_SUCCESS) {
+        RENDERER_LOGD("Could not disable v-sync (%x)", error);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Tracing and debugging
+// ----------------------------------------------------------------------------
+
+static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz) {
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLSurface surf = eglGetCurrentSurface(EGL_DRAW);
+    eglBeginFrame(dpy, surf);
+}
+
+#endif // USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// Shaders
 // ----------------------------------------------------------------------------
 
 static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
@@ -38,12 +119,6 @@
     env->ReleaseStringUTFChars(diskCachePath, cacheArray);
 }
 
-static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz) {
-    EGLDisplay dpy = eglGetCurrentDisplay();
-    EGLSurface surf = eglGetCurrentSurface(EGL_DRAW);
-    eglBeginFrame(dpy, surf);
-}
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -51,10 +126,20 @@
 const char* const kClassPathName = "android/view/HardwareRenderer";
 
 static JNINativeMethod gMethods[] = {
-    { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
-            (void*) android_view_HardwareRenderer_setupShadersDiskCache },
+#ifdef USE_OPENGL_RENDERER
+    { "nIsBackBufferPreserved", "()Z",
+            (void*) android_view_HardwareRenderer_isBackBufferPreserved },
+    { "nPreserveBackBuffer",    "()Z",
+            (void*) android_view_HardwareRenderer_preserveBackBuffer },
+    { "nDisableVsync",          "()V",
+            (void*) android_view_HardwareRenderer_disableVsync },
+
     { "nBeginFrame", "()V",
             (void*) android_view_HardwareRenderer_beginFrame },
+#endif
+
+    { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
+            (void*) android_view_HardwareRenderer_setupShadersDiskCache },
 };
 
 int register_android_view_HardwareRenderer(JNIEnv* env) {
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
new file mode 100644
index 0000000..73da84f
--- /dev/null
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -0,0 +1,327 @@
+/*
+ * 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.text;
+
+import static android.text.Layout.Alignment.*;
+
+import android.text.DynamicLayout;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests DynamciLayout updateBlocks method.
+ *
+ * Requires disabling access checks in the vm since this calls package-private APIs.
+ *
+ * @Suppress
+ */
+public class DynamicLayoutBlocksTest extends TestCase {
+    private DynamicLayout dl = new DynamicLayout("", new TextPaint(), 0, ALIGN_NORMAL, 0, 0, false);
+    private static final int ___ = DynamicLayout.INVALID_BLOCK_INDEX;
+
+    private int[] initialBlockEnds;
+    private int[] initialBlockIndices;
+
+    private void defineInitialState(int[] ends, int[] indices) {
+        initialBlockEnds = ends;
+        initialBlockIndices = indices;
+        assertEquals(initialBlockEnds.length, initialBlockIndices.length);
+    }
+
+    public void printBlocks(String message) {
+        System.out.print(message);
+        for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
+            System.out.print("  " + Integer.toString(dl.getBlockEnds()[i]));
+        }
+        System.out.println();
+    }
+
+    public void checkInvariants() {
+        assertTrue(dl.getNumberOfBlocks() > 0);
+        assertTrue(dl.getNumberOfBlocks() <= dl.getBlockEnds().length);
+        assertEquals(dl.getBlockEnds().length, dl.getBlockIndices().length);
+
+        for (int i = 1; i < dl.getNumberOfBlocks(); i++) {
+            assertTrue(dl.getBlockEnds()[i] > dl.getBlockEnds()[i-1]);
+        }
+    }
+
+    private void update(int startLine, int endLine, int newLineCount) {
+        dl.setBlocksDataForTest(initialBlockEnds, initialBlockIndices, initialBlockEnds.length);
+        checkInvariants();
+        dl.updateBlocks(startLine, endLine, newLineCount);
+    }
+
+    private void assertState(int[] sizes, int[] indices) {
+        checkInvariants();
+
+        assertEquals(sizes.length, dl.getNumberOfBlocks());
+        assertEquals(indices.length, dl.getNumberOfBlocks());
+
+        int[] ends = new int[sizes.length];
+        for (int i = 0; i < ends.length; i++) {
+            ends[i] = i == 0 ? (sizes[0] == 0 ? 0 : sizes[0] - 1) : ends[i - 1] + sizes[i];
+        }
+
+        for (int i = 0; i < dl.getNumberOfBlocks(); i++) {
+            assertEquals(ends[i], dl.getBlockEnds()[i]);
+            assertEquals(indices[i], dl.getBlockIndices()[i]);
+        }
+    }
+
+    private void assertState(int[] sizes) {
+        int[] ids = new int[sizes.length];
+        for (int i = 0; i < sizes.length; i++) {
+            ids[i] = DynamicLayout.INVALID_BLOCK_INDEX;
+        }
+        assertState(sizes, ids);
+    }
+
+    public void testFrom0() {
+        defineInitialState( new int[] { 0 }, new int[] { 123 });
+
+        update(0, 0, 0);
+        assertState( new int[] { 0 } );
+
+        update(0, 0, 1);
+        assertState( new int[] { 0 } );
+
+        update(0, 0, 10);
+        assertState( new int[] { 10 } );
+    }
+
+    public void testFrom1ReplaceByEmpty() {
+        defineInitialState( new int[] { 100 }, new int[] { 123 });
+
+        update(0, 0, 0);
+        assertState( new int[] { 100 } );
+
+        update(0, 10, 0);
+        assertState( new int[] { 90 } );
+
+        update(0, 100, 0);
+        assertState( new int[] { 0 } );
+
+        update(20, 30, 0);
+        assertState( new int[] { 20, 70 } );
+
+        update(20, 20, 0);
+        assertState( new int[] { 20, 80 } );
+
+        update(40, 100, 0);
+        assertState( new int[] { 40 } );
+
+        update(100, 100, 0);
+        assertState( new int[] { 100 } );
+    }
+
+    public void testFrom1ReplaceFromFirstLine() {
+        defineInitialState( new int[] { 100 }, new int[] { 123 });
+
+        update(0, 0, 1);
+        assertState( new int[] { 0, 100 } );
+
+        update(0, 0, 10);
+        assertState( new int[] { 10, 100 } );
+
+        update(0, 30, 31);
+        assertState( new int[] { 31, 70 } );
+
+        update(0, 100, 20);
+        assertState( new int[] { 20 } );
+    }
+
+    public void testFrom1ReplaceFromCenter() {
+        defineInitialState( new int[] { 100 }, new int[] { 123 });
+
+        update(20, 20, 1);
+        assertState( new int[] { 20, 1, 80 } );
+
+        update(20, 20, 10);
+        assertState( new int[] { 20, 10, 80 } );
+
+        update(20, 30, 50);
+        assertState( new int[] { 20, 50, 70 } );
+
+        update(20, 100, 50);
+        assertState( new int[] { 20, 50 } );
+    }
+
+    public void testFrom1ReplaceFromEnd() {
+        defineInitialState( new int[] { 100 }, new int[] { 123 });
+
+        update(100, 100, 0);
+        assertState( new int[] { 100 } );
+
+        update(100, 100, 1);
+        assertState( new int[] { 100, 1 } );
+
+        update(100, 100, 10);
+        assertState( new int[] { 100, 10 } );
+    }
+
+    public void testFrom2ReplaceFromFirstLine() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(0, 4, 50);
+        assertState( new int[] { 50, 10-4, 20-10 }, new int[] { ___, ___, 456 } );
+
+        update(0, 10, 50);
+        assertState( new int[] { 50, 20-10 }, new int[] { ___, 456 } );
+
+        update(0, 15, 50);
+        assertState( new int[] { 50, 20-15 }, new int[] { ___, ___ } );
+
+        update(0, 20, 50);
+        assertState( new int[] { 50 }, new int[] { ___ } );
+    }
+
+    public void testFrom2ReplaceFromFirstBlock() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(3, 7, 50);
+        assertState( new int[] { 3, 50, 10-7, 20-10 }, new int[] { ___, ___, ___, 456 } );
+
+        update(3, 10, 50);
+        assertState( new int[] { 3, 50, 20-10 }, new int[] { ___, ___, 456 } );
+
+        update(3, 14, 50);
+        assertState( new int[] { 3, 50, 20-14 }, new int[] { ___, ___, ___ } );
+
+        update(3, 20, 50);
+        assertState( new int[] { 3, 50 }, new int[] { ___, ___ } );
+    }
+
+    public void testFrom2ReplaceFromBottomBoundary() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(10, 10, 50);
+        assertState( new int[] { 10, 50, 20-10 }, new int[] { ___, ___, 456 } );
+
+        update(10, 14, 50);
+        assertState( new int[] { 10, 50, 20-14 }, new int[] { ___, ___, ___ } );
+
+        update(10, 20, 50);
+        assertState( new int[] { 10, 50 }, new int[] { ___, ___ } );
+    }
+
+    public void testFrom2ReplaceFromTopBoundary() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(11, 11, 50);
+        assertState( new int[] { 11, 50, 20-11 }, new int[] { 123, ___, ___ } );
+
+        update(11, 14, 50);
+        assertState( new int[] { 11, 50, 20-14 }, new int[] { 123, ___, ___ } );
+
+        update(11, 20, 50);
+        assertState( new int[] { 11, 50 }, new int[] { 123, ___ } );
+    }
+
+    public void testFrom2ReplaceFromSecondBlock() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(14, 14, 50);
+        assertState( new int[] { 11, 14-11, 50, 20-14 }, new int[] { 123, ___, ___, ___ } );
+
+        update(14, 17, 50);
+        assertState( new int[] { 11, 14-11, 50, 20-17 }, new int[] { 123, ___, ___, ___ } );
+
+        update(14, 20, 50);
+        assertState( new int[] { 11, 14-11, 50 }, new int[] { 123, ___, ___ } );
+    }
+
+    public void testFrom2RemoveFromFirst() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(0, 4, 0);
+        assertState( new int[] { 10-4, 20-10 }, new int[] { ___, 456 } );
+
+        update(0, 10, 0);
+        assertState( new int[] { 20-10 }, new int[] { 456 } );
+
+        update(0, 14, 0);
+        assertState( new int[] { 20-14 }, new int[] { ___ } );
+
+        update(0, 20, 0);
+        assertState( new int[] { 0 }, new int[] { ___ } );
+    }
+
+    public void testFrom2RemoveFromFirstBlock() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(4, 7, 0);
+        assertState( new int[] { 4, 10-7, 20-10 }, new int[] { ___, ___, 456 } );
+
+        update(4, 10, 0);
+        assertState( new int[] { 4, 20-10 }, new int[] { ___, 456 } );
+
+        update(4, 14, 0);
+        assertState( new int[] { 4, 20-14 }, new int[] { ___, ___ } );
+
+        update(4, 20, 0);
+        assertState( new int[] { 4 }, new int[] { ___ } );
+    }
+
+    public void testFrom2RemoveFromSecondBlock() {
+        defineInitialState( new int[] { 10, 20 }, new int[] { 123, 456 });
+
+        update(14, 17, 0);
+        assertState( new int[] { 11, 14-11, 20-17 }, new int[] { 123, ___, ___ } );
+
+        update(14, 20, 0);
+        assertState( new int[] { 11, 14-11 }, new int[] { 123, ___ } );
+    }
+
+    public void testFrom3ReplaceFromFirstBlock() {
+        defineInitialState( new int[] { 10, 30, 60 }, new int[] { 123, 456, 789 });
+
+        update(3, 7, 50);
+        assertState( new int[] { 3, 50, 10-7, 30-10, 60-30 }, new int[] { ___, ___, ___, 456, 789 } );
+
+        update(3, 10, 50);
+        assertState( new int[] { 3, 50, 30-10, 60-30 }, new int[] { ___, ___, 456, 789 } );
+
+        update(3, 17, 50);
+        assertState( new int[] { 3, 50, 30-17, 60-30 }, new int[] { ___, ___, ___, 789 } );
+
+        update(3, 30, 50);
+        assertState( new int[] { 3, 50, 60-30 }, new int[] { ___, ___, 789 } );
+
+        update(3, 40, 50);
+        assertState( new int[] { 3, 50, 60-40 }, new int[] { ___, ___, ___ } );
+
+        update(3, 60, 50);
+        assertState( new int[] { 3, 50 }, new int[] { ___, ___ } );
+    }
+
+    public void testFrom3ReplaceFromSecondBlock() {
+        defineInitialState( new int[] { 10, 30, 60 }, new int[] { 123, 456, 789 });
+
+        update(13, 17, 50);
+        assertState( new int[] { 11, 2, 50, 30-17, 60-30 }, new int[] { 123, ___, ___, ___, 789 } );
+
+        update(13, 30, 50);
+        assertState( new int[] { 11, 2, 50, 60-30 }, new int[] { 123, ___, ___, 789 } );
+
+        update(13, 40, 50);
+        assertState( new int[] { 11, 2, 50, 60-40 }, new int[] { 123, ___, ___, ___ } );
+
+        update(13, 60, 50);
+        assertState( new int[] { 11, 2, 50 }, new int[] { 123, ___, ___ } );
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index c406fa0..f07e0de 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -560,18 +560,12 @@
          */
         private void handleHostApEvents(String dataString) {
             String[] tokens = dataString.split(" ");
-            /* AP-STA-CONNECTED 42:fc:89:a8:96:09 dev_addr=02:90:4c:a0:92:54 */
+            /* AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
             if (tokens[0].equals(AP_STA_CONNECTED_STR)) {
-                String[] nameValue = tokens[2].split("=");
-                if (nameValue.length != 2) return;
-                WifiP2pDevice device = new WifiP2pDevice();
-                device.interfaceAddress = tokens[1];
-                device.deviceAddress = nameValue[1];
-                mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, device);
-            /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
+                mStateMachine.sendMessage(AP_STA_CONNECTED_EVENT, new WifiP2pDevice(dataString));
+            /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=02:90:4c:a0:92:54 */
             } else if (tokens[0].equals(AP_STA_DISCONNECTED_STR)) {
-                //TODO: fix this once wpa_supplicant reports this consistently
-                mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, tokens[1]);
+                mStateMachine.sendMessage(AP_STA_DISCONNECTED_EVENT, new WifiP2pDevice(dataString));
             }
         }
 
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 91f2379..c11d082 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -577,26 +577,6 @@
     }
 
 
-    public String p2pGetInterfaceAddress(String deviceAddress) {
-        if (TextUtils.isEmpty(deviceAddress)) return null;
-
-        //  "p2p_peer deviceAddress" returns a multi-line result containing
-        //      intended_addr=fa:7b:7a:42:82:13
-        String peerInfo = p2pPeer(deviceAddress);
-        if (TextUtils.isEmpty(peerInfo)) return null;
-        String[] tokens= peerInfo.split("\n");
-
-        for (String token : tokens) {
-            //TODO: update from interface_addr when wpa_supplicant implementation is fixed
-            if (token.startsWith("intended_addr=")) {
-                String[] nameValue = token.split("=");
-                if (nameValue.length != 2) break;
-                return nameValue[1];
-            }
-        }
-        return null;
-    }
-
     public String p2pGetDeviceAddress() {
         String status = status();
         if (status == null) return "";
@@ -612,6 +592,13 @@
         return "";
     }
 
+    public boolean isGroupOwner(String deviceAddress) {
+        /* BSS returns details only for a GO */
+        String bssInfo = doStringCommand("BSS p2p_dev_addr=" + deviceAddress);
+        if (TextUtils.isEmpty(bssInfo)) return false;
+        return true;
+    }
+
     public String p2pPeer(String deviceAddress) {
         return doStringCommand("P2P_PEER " + deviceAddress);
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index b0cde64..afdc9be 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 
 import java.util.regex.Pattern;
+import java.util.regex.Matcher;
 
 /**
  * A class representing a Wi-Fi p2p device
@@ -42,17 +43,6 @@
     public String deviceAddress = "";
 
     /**
-     * interfaceAddress
-     *
-     * This address is used during group owner negotiation as the Intended
-     * P2P Interface Address and the group interface will be created with
-     * address as the local address in case of successfully completed
-     * negotiation.
-     * @hide
-     */
-    public String interfaceAddress;
-
-    /**
      * Primary device type identifies the type of device. For example, an application
      * could filter the devices discovered to only display printers if the purpose is to
      * enable a printing action from the user. See the Wi-Fi Direct technical specification
@@ -117,6 +107,43 @@
     /** Device connection status */
     public int status = UNAVAILABLE;
 
+    /** Detailed device string pattern
+     * 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
+     *
+     */
+    private static final Pattern detailedDevicePattern = Pattern.compile(
+        "((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " +
+        "(\\d+ )?" +
+        "p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " +
+        "pri_dev_type=(\\d+-[0-9a-fA-F]+-\\d+) " +
+        "name='(.*)' " +
+        "config_methods=(0x[0-9a-fA-F]+) " +
+        "dev_capab=(0x[0-9a-fA-F]+) " +
+        "group_capab=(0x[0-9a-fA-F]+)"
+    );
+
+    /** 2 token device address pattern
+     * Example:
+     *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
+     *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09
+     */
+    private static final Pattern twoTokenPattern = Pattern.compile(
+        "(p2p_dev_addr=)?((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
+    );
+
+    /** 3 token device address pattern
+     * Example:
+     *  AP-STA-CONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13
+     *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09 p2p_dev_addr=fa:7b:7a:42:02:13
+     */
+    private static final Pattern threeTokenPattern = Pattern.compile(
+        "(?:[0-9a-f]{2}:){5}[0-9a-f]{2} p2p_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
+    );
+
+
     public WifiP2pDevice() {
     }
 
@@ -128,6 +155,10 @@
      *
      *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
      *
+     *  AP-STA-CONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54]
+     *
+     *  AP-STA-DISCONNECTED 42:fc:89:a8:96:09 [p2p_dev_addr=02:90:4c:a0:92:54]
+     *
      *  fa:7b:7a:42:02:13
      *
      *  Note: The events formats can be looked up in the wpa_supplicant code
@@ -135,56 +166,44 @@
      */
     public WifiP2pDevice(String string) throws IllegalArgumentException {
         String[] tokens = string.split("[ \n]");
+        Matcher match;
 
         if (tokens.length < 1) {
             throw new IllegalArgumentException("Malformed supplicant event");
         }
 
-        /* Just a device address */
-        if (tokens.length == 1) {
-            deviceAddress = string;
-            return;
-        }
-
-        for (String token : tokens) {
-            String[] nameValue = token.split("=");
-            if (nameValue.length != 2) {
-                //mac address without key is device address
-                if (token.matches("(([0-9a-f]{2}:){5}[0-9a-f]{2})")) {
-                    deviceAddress = token;
+        switch (tokens.length) {
+            case 1:
+                /* Just a device address */
+                deviceAddress = string;
+                return;
+            case 2:
+                match = twoTokenPattern.matcher(string);
+                if (!match.find()) {
+                    throw new IllegalArgumentException("Malformed supplicant event");
                 }
-                continue;
-            }
+                deviceAddress = match.group(2);
+                return;
+            case 3:
+                match = threeTokenPattern.matcher(string);
+                if (!match.find()) {
+                    throw new IllegalArgumentException("Malformed supplicant event");
+                }
+                deviceAddress = match.group(1);
+                return;
+            default:
+                match = detailedDevicePattern.matcher(string);
+                if (!match.find()) {
+                    throw new IllegalArgumentException("Malformed supplicant event");
+                }
 
-            if (nameValue[0].equals("p2p_dev_addr")) {
-                deviceAddress = nameValue[1];
-                continue;
-            }
-
-            if (nameValue[0].equals("pri_dev_type")) {
-                primaryDeviceType = nameValue[1];
-                continue;
-            }
-
-            if (nameValue[0].equals("name") || nameValue[0].equals("device_name")) {
-                deviceName = trimQuotes(nameValue[1]);
-                continue;
-            }
-
-            if (nameValue[0].equals("config_methods")) {
-                wpsConfigMethodsSupported = parseHex(nameValue[1]);
-                continue;
-            }
-
-            if (nameValue[0].equals("dev_capab")) {
-                deviceCapability = parseHex(nameValue[1]);
-                continue;
-            }
-
-            if (nameValue[0].equals("group_capab")) {
-                groupCapability = parseHex(nameValue[1]);
-                continue;
-            }
+                deviceAddress = match.group(3);
+                primaryDeviceType = match.group(4);
+                deviceName = match.group(5);
+                wpsConfigMethodsSupported = parseHex(match.group(6));
+                deviceCapability = parseHex(match.group(7));
+                groupCapability = parseHex(match.group(8));
+                break;
         }
 
         if (tokens[0].startsWith("P2P-DEVICE-FOUND")) {
@@ -233,7 +252,6 @@
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("Device: ").append(deviceName);
         sbuf.append("\n deviceAddress: ").append(deviceAddress);
-        sbuf.append("\n interfaceAddress: ").append(interfaceAddress);
         sbuf.append("\n primary type: ").append(primaryDeviceType);
         sbuf.append("\n secondary type: ").append(secondaryDeviceType);
         sbuf.append("\n wps: ").append(wpsConfigMethodsSupported);
@@ -253,7 +271,6 @@
         if (source != null) {
             deviceName = source.deviceName;
             deviceAddress = source.deviceAddress;
-            interfaceAddress = source.interfaceAddress;
             primaryDeviceType = source.primaryDeviceType;
             secondaryDeviceType = source.secondaryDeviceType;
             wpsConfigMethodsSupported = source.wpsConfigMethodsSupported;
@@ -267,7 +284,6 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(deviceName);
         dest.writeString(deviceAddress);
-        dest.writeString(interfaceAddress);
         dest.writeString(primaryDeviceType);
         dest.writeString(secondaryDeviceType);
         dest.writeInt(wpsConfigMethodsSupported);
@@ -283,7 +299,6 @@
                 WifiP2pDevice device = new WifiP2pDevice();
                 device.deviceName = in.readString();
                 device.deviceAddress = in.readString();
-                device.interfaceAddress = in.readString();
                 device.primaryDeviceType = in.readString();
                 device.secondaryDeviceType = in.readString();
                 device.wpsConfigMethodsSupported = in.readInt();
@@ -298,15 +313,6 @@
             }
         };
 
-    private String trimQuotes(String str) {
-        str = str.trim();
-        if (str.startsWith("'") && str.endsWith("'")) {
-            if (str.length() <= 2) return "";
-            else return str.substring(1, str.length()-1);
-        }
-        return str;
-    }
-
     //supported formats: 0x1abc, 0X1abc, 1abc
     private int parseHex(String hexString) {
         int num = 0;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index cbb4e81..9ce2545 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -80,19 +80,6 @@
     }
 
     /** @hide */
-    public void updateInterfaceAddress(WifiP2pDevice device) {
-        for (WifiP2pDevice d : mDevices) {
-            //Found, update interface address
-            if (d.equals(device)) {
-                d.interfaceAddress = device.interfaceAddress;
-                return;
-            }
-        }
-        //Not found, add a new one
-        mDevices.add(device);
-    }
-
-    /** @hide */
     public boolean remove(WifiP2pDevice device) {
         if (device == null) return false;
         return mDevices.remove(device);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index e141aba..c30cc73 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -23,6 +23,8 @@
 import java.util.List;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
 
 /**
  * A class representing a Wi-Fi P2p group
@@ -48,6 +50,15 @@
 
     private String mInterface;
 
+    /** P2P group started string pattern */
+    private static final Pattern groupStartedPattern = Pattern.compile(
+        "ssid=\"(.+)\" " +
+        "freq=(\\d+) " +
+        "(?:psk=)?([0-9a-fA-F]{64})?" +
+        "(?:passphrase=)?(?:\"(.{8,63})\")? " +
+        "go_dev_addr=((?:[0-9a-f]{2}:){5}[0-9a-f]{2})"
+    );
+
     public WifiP2pGroup() {
     }
 
@@ -78,24 +89,18 @@
             mInterface = tokens[1];
             mIsGroupOwner = tokens[2].equals("GO");
 
-            for (String token : tokens) {
-                String[] nameValue = token.split("=");
-                if (nameValue.length != 2) continue;
-
-                if (nameValue[0].equals("ssid")) {
-                    mNetworkName = nameValue[1];
-                    continue;
-                }
-
-                if (nameValue[0].equals("passphrase")) {
-                    mPassphrase = nameValue[1];
-                    continue;
-                }
-
-                if (nameValue[0].equals("go_dev_addr")) {
-                    mOwner = new WifiP2pDevice(nameValue[1]);
-                }
+            Matcher match = groupStartedPattern.matcher(supplicantEvent);
+            if (!match.find()) {
+                return;
             }
+
+            mNetworkName = match.group(1);
+            //freq and psk are unused right now
+            //int freq = Integer.parseInt(match.group(2));
+            //String psk = match.group(3);
+            mPassphrase = match.group(4);
+            mOwner = new WifiP2pDevice(match.group(5));
+
         } else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
             for (String token : tokens) {
                 String[] nameValue = token.split("=");
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 399dc9d..02ca926 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -541,8 +541,6 @@
                 case WifiP2pManager.CONNECT:
                     if (DBG) logd(getName() + " sending connect");
                     mSavedPeerConfig = (WifiP2pConfig) message.obj;
-                    String updatedPeerDetails = mWifiNative.p2pPeer(mSavedPeerConfig.deviceAddress);
-                    mPeers.update(new WifiP2pDevice(updatedPeerDetails));
                     mPersistGroup = false;
                     int netId = configuredNetworkId(mSavedPeerConfig.deviceAddress);
                     if (netId >= 0) {
@@ -553,7 +551,7 @@
                         mWifiNative.p2pStopFind();
                         //If peer is a GO, we do not need to send provisional discovery,
                         //the supplicant takes care of it.
-                        if (isGroupOwner(mSavedPeerConfig.deviceAddress)) {
+                        if (mWifiNative.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
                             p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
                             transitionTo(mGroupNegotiationState);
                         } else {
@@ -683,7 +681,7 @@
             switch (message.what) {
                 case PEER_CONNECTION_USER_ACCEPT:
                     //TODO: handle persistence
-                    if (isGroupOwner(mSavedPeerConfig.deviceAddress)) {
+                    if (mWifiNative.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
                         p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
                     } else {
                         p2pConnectWithPinDisplay(mSavedPeerConfig, FORM_GROUP);
@@ -842,7 +840,6 @@
                     String deviceAddress = device.deviceAddress;
                     if (deviceAddress != null) {
                         mGroup.addClient(deviceAddress);
-                        mPeers.updateInterfaceAddress(device);
                         updateDeviceStatus(deviceAddress, WifiP2pDevice.CONNECTED);
                         if (DBG) logd(getName() + " ap sta connected");
                         sendP2pPeersChangedBroadcast();
@@ -851,10 +848,8 @@
                     }
                     break;
                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
-                    //TODO: the disconnection event is still inconsistent and reports
-                    //interface address. Fix this after wpa_supplicant is fixed.
-                    String interfaceAddress = (String) message.obj;
-                    deviceAddress = getDeviceAddress(interfaceAddress);
+                    device = (WifiP2pDevice) message.obj;
+                    deviceAddress = device.deviceAddress;
                     if (deviceAddress != null) {
                         updateDeviceStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
                         if (mGroup.removeClient(deviceAddress)) {
@@ -872,7 +867,7 @@
                         sendP2pPeersChangedBroadcast();
                         if (DBG) loge(getName() + " ap sta disconnected");
                     } else {
-                        loge("Disconnect on unknown interface address : " + interfaceAddress);
+                        loge("Disconnect on unknown device: " + device);
                     }
                     break;
                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
@@ -883,6 +878,7 @@
                         setWifiP2pInfoOnGroupFormation(dhcpInfo.serverAddress);
                         sendP2pConnectionChangedBroadcast();
                     } else {
+                        loge("DHCP failed");
                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
                     }
                     break;
@@ -916,6 +912,7 @@
                     }
 
                     mGroup = null;
+                    mWifiNative.p2pFlush();
                     if (changed) sendP2pPeersChangedBroadcast();
                     transitionTo(mInactiveState);
                     break;
@@ -1183,15 +1180,6 @@
         }
     }
 
-    private boolean isGroupOwner(String deviceAddress) {
-        for (WifiP2pDevice d : mPeers.getDeviceList()) {
-            if (d.deviceAddress.equals(deviceAddress)) {
-                return d.isGroupOwner();
-            }
-        }
-        return false;
-    }
-
     //TODO: implement when wpa_supplicant is fixed
     private int configuredNetworkId(String deviceAddress) {
         return -1;
@@ -1219,15 +1207,6 @@
         return deviceAddress;
     }
 
-    private String getDeviceAddress(String interfaceAddress) {
-        for (WifiP2pDevice d : mPeers.getDeviceList()) {
-            if (interfaceAddress.equals(d.interfaceAddress)) {
-                return d.deviceAddress;
-            }
-        }
-        return null;
-    }
-
     private WifiP2pDevice getDeviceFromPeerList(String deviceAddress) {
         for (WifiP2pDevice d : mPeers.getDeviceList()) {
             if (d.deviceAddress.equals(deviceAddress)) {