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)) {