Merge "Fix tap gesture on touch pads."
diff --git a/api/current.txt b/api/current.txt
index eb58ae4..e0afd5b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9235,7 +9235,11 @@
 
   public static class Camera.Face {
     ctor public Camera.Face();
+    field public int id;
+    field public android.graphics.Point leftEye;
+    field public android.graphics.Point mouth;
     field public android.graphics.Rect rect;
+    field public android.graphics.Point rightEye;
     field public int score;
   }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 879c441..08bb133 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1162,6 +1162,43 @@
          * @see #startFaceDetection(int)
          */
         public int score;
+
+        /**
+         * An unique id per face while the face is visible to the tracker. If
+         * the face leaves the field-of-view and comes back, it will get a new
+         * id. This is an optional field, may not be supported on all devices.
+         * If not supported, id will always be set to -1. The optional fields
+         * are supported as a set. Either they are all valid, or none of them
+         * are.
+         */
+        public int id = -1;
+
+        /**
+         * The coordinates of the center of the left eye. The coordinates are in
+         * the same space as the ones for {@link #rect}. This is an optional
+         * field, may not be supported on all devices. If not supported, the
+         * value will always be set to null. The optional fields are supported
+         * as a set. Either they are all valid, or none of them are.
+         */
+        public Point leftEye = null;
+
+        /**
+         * The coordinates of the center of the right eye. The coordinates are
+         * in the same space as the ones for {@link #rect}.This is an optional
+         * field, may not be supported on all devices. If not supported, the
+         * value will always be set to null. The optional fields are supported
+         * as a set. Either they are all valid, or none of them are.
+         */
+        public Point rightEye = null;
+
+        /**
+         * The coordinates of the center of the mouth.  The coordinates are in
+         * the same space as the ones for {@link #rect}. This is an optional
+         * field, may not be supported on all devices. If not supported, the
+         * value will always be set to null. The optional fields are supported
+         * as a set. Either they are all valid, or none of them are.
+         */
+        public Point mouth = null;
     }
 
     // Error codes match the enum in include/ui/Camera.h
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index b72222e..9d959fb 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -261,6 +261,7 @@
     @Override
     public final void draw(Canvas canvas) {
         applyUpdate();
+        applyTransformMatrix();
     }
 
     /**
@@ -315,11 +316,7 @@
         }
 
         applyUpdate();
-
-        if (mMatrixChanged) {
-            mLayer.setTransform(mMatrix);
-            mMatrixChanged = false;
-        }
+        applyTransformMatrix();
 
         return mLayer;
     }
@@ -386,7 +383,7 @@
     public void setTransform(Matrix transform) {
         mMatrix.set(transform);
         mMatrixChanged = true;
-        invalidate();
+        invalidateParentIfNeeded();
     }
 
     /**
@@ -410,6 +407,13 @@
         return transform;
     }
 
+    private void applyTransformMatrix() {
+        if (mMatrixChanged) {
+            mLayer.setTransform(mMatrix);
+            mMatrixChanged = false;
+        }
+    }
+
     /**
      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
      * of the associated surface texture. If the surface texture is not available,
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_ime.png b/core/res/res/drawable-hdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..29a7989
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_ime.png b/core/res/res/drawable-mdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..b27e059
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png b/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..a40ddeb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 4c44049c..bc86ab7 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -133,13 +133,14 @@
 
     <!-- Column 2 - password entry field and PIN keyboard -->
     <LinearLayout
-        android:orientation="vertical"
+        android:orientation="horizontal"
         android:layout_width="270dip"
         android:layout_gravity="center_vertical">
 
         <EditText android:id="@+id/passwordEntry"
             android:layout_height="wrap_content"
-            android:layout_width="match_parent"
+            android:layout_width="0dip"
+            android:layout_weight="1"
             android:gravity="center"
             android:singleLine="true"
             android:textStyle="normal"
@@ -153,6 +154,17 @@
             android:suggestionsEnabled="false"
             />
 
+        <ImageView android:id="@+id/switch_ime_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_lockscreen_ime"
+            android:clickable="true"
+            android:padding="8dip"
+            android:layout_gravity="center"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone"
+            />
+
     </LinearLayout>
 
     <!-- Numeric keyboard -->
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index 1d0ea547..994c439 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -95,22 +95,39 @@
         />
 
     <!-- Password entry field -->
-    <EditText android:id="@+id/passwordEntry"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
+    <LinearLayout
         android:layout_gravity="center_vertical|fill_horizontal"
-        android:gravity="center_horizontal"
-        android:singleLine="true"
-        android:textStyle="normal"
-        android:inputType="textPassword"
-        android:textSize="36sp"
+        android:orientation="horizontal"
         android:layout_marginLeft="16dip"
-        android:layout_marginRight="16dip"
-        android:background="@drawable/lockscreen_password_field_dark"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="#ffffffff"
-        android:imeOptions="actionDone"
-        android:suggestionsEnabled="false"/>
+        android:layout_marginRight="16dip">
+
+        <EditText android:id="@+id/passwordEntry"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center_horizontal"
+            android:singleLine="true"
+            android:textStyle="normal"
+            android:inputType="textPassword"
+            android:textSize="36sp"
+            android:background="@drawable/lockscreen_password_field_dark"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="#ffffffff"
+            android:imeOptions="actionDone"
+            android:suggestionsEnabled="false"/>
+
+        <ImageView android:id="@+id/switch_ime_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_lockscreen_ime"
+            android:clickable="true"
+            android:padding="8dip"
+            android:layout_gravity="center"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone"
+            />
+
+    </LinearLayout>
 
     <!-- Numeric keyboard -->
     <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 7c1f93a..d70b3bb 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.policy.impl;
 
+import java.util.List;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -27,18 +29,18 @@
 import android.os.CountDownTimer;
 import android.os.SystemClock;
 import android.security.KeyStore;
-import android.telephony.TelephonyManager;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextWatcher;
 import android.text.method.DigitsKeyListener;
 import android.text.method.TextKeyListener;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -159,6 +161,68 @@
                 }
             }
         });
+
+        // If there's more than one IME, enable the IME switcher button
+        View switchImeButton = findViewById(R.id.switch_ime_button);
+        final InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        if (switchImeButton != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
+            switchImeButton.setVisibility(View.VISIBLE);
+            switchImeButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.pokeWakelock(); // Leave the screen on a bit longer
+                    imm.showInputMethodPicker();
+                }
+            });
+        }
+    }
+
+    /**
+     * Method adapted from com.android.inputmethod.latin.Utils
+     *
+     * @param imm The input method manager
+     * @param shouldIncludeAuxiliarySubtypes
+     * @return true if we have multiple IMEs to choose from
+     */
+    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+            final boolean shouldIncludeAuxiliarySubtypes) {
+        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
+
+        // Number of the filtered IMEs
+        int filteredImisCount = 0;
+
+        for (InputMethodInfo imi : enabledImis) {
+            // We can return true immediately after we find two or more filtered IMEs.
+            if (filteredImisCount > 1) return true;
+            final List<InputMethodSubtype> subtypes =
+                    imm.getEnabledInputMethodSubtypeList(imi, true);
+            // IMEs that have no subtypes should be counted.
+            if (subtypes.isEmpty()) {
+                ++filteredImisCount;
+                continue;
+            }
+
+            int auxCount = 0;
+            for (InputMethodSubtype subtype : subtypes) {
+                if (subtype.isAuxiliary()) {
+                    ++auxCount;
+                }
+            }
+            final int nonAuxCount = subtypes.size() - auxCount;
+
+            // IMEs that have one or more non-auxiliary subtypes should be counted.
+            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+            // subtypes should be counted as well.
+            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+                ++filteredImisCount;
+                continue;
+            }
+        }
+
+        return filteredImisCount > 1
+        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
+        // input method subtype (The current IME should be LatinIME.)
+                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
     }
 
     @Override
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 291ce75..800c4fc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1074,7 +1074,7 @@
                     int uid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    forceStopPackageLocked(pkg, uid, restart, false, true);
+                    forceStopPackageLocked(pkg, uid, restart, false, true, false);
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -3086,7 +3086,7 @@
                     return;
                 }
                 killPackageProcessesLocked(packageName, pkgUid,
-                        ProcessList.SECONDARY_SERVER_ADJ, false, true, true);
+                        ProcessList.SECONDARY_SERVER_ADJ, false, true, true, false);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -3244,7 +3244,7 @@
     }
 
     private void forceStopPackageLocked(final String packageName, int uid) {
-        forceStopPackageLocked(packageName, uid, false, false, true);
+        forceStopPackageLocked(packageName, uid, false, false, true, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -3257,7 +3257,8 @@
     }
     
     private final boolean killPackageProcessesLocked(String packageName, int uid,
-            int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit) {
+            int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit,
+            boolean evenPersistent) {
         ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
 
         // Remove all processes this package may have touched: all with the
@@ -3268,7 +3269,7 @@
             final int NA = apps.size();
             for (int ia=0; ia<NA; ia++) {
                 ProcessRecord app = apps.valueAt(ia);
-                if (app.persistent) {
+                if (app.persistent && !evenPersistent) {
                     // we don't kill persistent processes
                     continue;
                 }
@@ -3298,7 +3299,8 @@
     }
 
     private final boolean forceStopPackageLocked(String name, int uid,
-            boolean callerWillRestart, boolean purgeCache, boolean doit) {
+            boolean callerWillRestart, boolean purgeCache, boolean doit,
+            boolean evenPersistent) {
         int i;
         int N;
 
@@ -3322,12 +3324,12 @@
         }
         
         boolean didSomething = killPackageProcessesLocked(name, uid, -100,
-                callerWillRestart, false, doit);
+                callerWillRestart, false, doit, evenPersistent);
         
         for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             if (r.packageName.equals(name)
-                    && (r.app == null || !r.app.persistent)) {
+                    && (r.app == null || evenPersistent || !r.app.persistent)) {
                 if (!doit) {
                     return true;
                 }
@@ -3344,7 +3346,7 @@
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
         for (ServiceRecord service : mServices.values()) {
             if (service.packageName.equals(name)
-                    && (service.app == null || !service.app.persistent)) {
+                    && (service.app == null || evenPersistent || !service.app.persistent)) {
                 if (!doit) {
                     return true;
                 }
@@ -3757,7 +3759,7 @@
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
-                          if (forceStopPackageLocked(pkg, -1, false, false, false)) {
+                          if (forceStopPackageLocked(pkg, -1, false, false, false, false)) {
                               setResultCode(Activity.RESULT_OK);
                               return;
                           }
@@ -6183,7 +6185,7 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                forceStopPackageLocked(packageName, -1, false, false, true);
+                forceStopPackageLocked(packageName, -1, false, false, true, true);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -11360,7 +11362,7 @@
                         String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                         if (list != null && (list.length > 0)) {
                             for (String pkg : list) {
-                                forceStopPackageLocked(pkg, -1, false, true, true);
+                                forceStopPackageLocked(pkg, -1, false, true, true, false);
                             }
                             sendPackageBroadcastLocked(
                                     IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list);
@@ -11371,7 +11373,7 @@
                         if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                             if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                                 forceStopPackageLocked(ssp,
-                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
+                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true, false);
                             }
                             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
@@ -12469,7 +12471,8 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
+            // Instrumentation can kill and relaunch even persistent processes
+            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true);
             ProcessRecord app = addAppLocked(ai);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12524,7 +12527,7 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        forceStopPackageLocked(app.processName, -1, false, false, true);
+        forceStopPackageLocked(app.processName, -1, false, false, true, true);
     }
 
     public void finishInstrumentation(IApplicationThread target,
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index d706af5..ff4786b 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -48,6 +48,7 @@
 static const float magSTDEV  = 0.5f;    // uT    (measured 0.7  / CDD 0.5)
 
 static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float SYMMETRY_TOLERANCE = 1e-10f;
 
 // -----------------------------------------------------------------------
 
@@ -134,10 +135,13 @@
 
 void Fusion::init() {
     mInitState = 0;
+
     mGyroRate = 0;
+
     mCount[0] = 0;
     mCount[1] = 0;
     mCount[2] = 0;
+
     mData = 0;
 }
 
@@ -267,19 +271,16 @@
     return NO_ERROR;
 }
 
-bool Fusion::checkState(const vec3_t& v) {
-    if (isnanf(length(v))) {
-        LOGW("9-axis fusion diverged. reseting state.");
+void Fusion::checkState() {
+    // P needs to stay positive semidefinite or the fusion diverges. When we
+    // detect divergence, we reset the fusion.
+    // TODO(braun): Instead, find the reason for the divergence and fix it.
+
+    if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) ||
+        !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) {
+        LOGW("Sensor fusion diverged; resetting state.");
         P = 0;
-        x1 = 0;
-        mInitState = 0;
-        mCount[0] = 0;
-        mCount[1] = 0;
-        mCount[2] = 0;
-        mData = 0;
-        return false;
     }
-    return true;
 }
 
 vec4_t Fusion::getAttitude() const {
@@ -327,6 +328,8 @@
     Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
 
     P = Phi*P*transpose(Phi) + GQGt;
+
+    checkState();
 }
 
 void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
@@ -365,6 +368,8 @@
     q += getF(q)*(0.5f*dq);
     x0 = normalize_quat(q);
     x1 += db;
+
+    checkState();
 }
 
 // -----------------------------------------------------------------------
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
index 556944b..7062999 100644
--- a/services/sensorservice/Fusion.h
+++ b/services/sensorservice/Fusion.h
@@ -37,7 +37,7 @@
     vec3_t  x1;
 
     /*
-     * the predicated covariance matrix is made of 4 3x3 sub-matrices and it
+     * the predicated covariance matrix is made of 4 3x3 sub-matrices and it is
      * semi-definite positive.
      *
      * P = | P00  P10 | = | P00  P10 |
@@ -74,7 +74,7 @@
     enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
     bool checkInitComplete(int, const vec3_t& w, float d = 0);
     void initFusion(const vec4_t& q0, float dT);
-    bool checkState(const vec3_t& v);
+    void checkState();
     void predict(const vec3_t& w, float dT);
     void update(const vec3_t& z, const vec3_t& Bi, float sigma);
     static mat34_t getF(const vec4_t& p);
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 1302ca3..a76fc91 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -295,6 +295,29 @@
     return r;
 }
 
+// Calculate the trace of a matrix
+template <typename TYPE, size_t C> static TYPE trace(const mat<TYPE, C, C>& m) {
+    TYPE t;
+    for (size_t i=0 ; i<C ; i++)
+        t += m[i][i];
+    return t;
+}
+
+// Test positive-semidefiniteness of a matrix
+template <typename TYPE, size_t C>
+static bool isPositiveSemidefinite(const mat<TYPE, C, C>& m, TYPE tolerance) {
+    for (size_t i=0 ; i<C ; i++)
+        if (m[i][i] < 0)
+            return false;
+
+    for (size_t i=0 ; i<C ; i++)
+      for (size_t j=i+1 ; j<C ; j++)
+          if (fabs(m[i][j] - m[j][i]) > tolerance)
+              return false;
+
+    return true;
+}
+
 // Transpose a vector
 template <
     template<typename T, size_t S> class VEC,
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index bfc4d5e..6c6f149 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -304,4 +304,28 @@
         return doBooleanCommand("P2P_INVITE group=" + group.getInterface()
                 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress);
     }
+
+    public static String p2pGetInterfaceAddress(String deviceAddress) {
+        if (deviceAddress == null) return null;
+
+        //  "p2p_peer deviceAddress" returns a multi-line result containing
+        //      intended_addr=fa:7b:7a:42:82:13
+        String peerInfo = p2pPeer(deviceAddress);
+        if (peerInfo == null) 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 static 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 83dc285..7908726 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -158,9 +158,6 @@
             return;
         }
 
-        Pattern p = Pattern.compile("(?:[0-9a-f]{2}:){5}[0-9a-f]{2}", Pattern.CASE_INSENSITIVE);
-        if (p.matcher(tokens[1]).matches()) interfaceAddress = tokens[1];
-
         for (String token : tokens) {
             String[] nameValue = token.split("=");
             if (nameValue.length != 2) continue;
@@ -177,6 +174,7 @@
 
             if (nameValue[0].equals("name")) {
                 deviceName = trimQuotes(nameValue[1]);
+                continue;
             }
 
             if (nameValue[0].equals("config_methods")) {
@@ -213,9 +211,7 @@
         if (other == null || other.deviceAddress == null) {
             return (deviceAddress == null);
         }
-        //STOPSHIP: fix later
-        //return other.deviceAddress.equals(deviceAddress);
-        return other.deviceAddress.startsWith(deviceAddress.substring(0,8));
+        return other.deviceAddress.equals(deviceAddress);
     }
 
     public String toString() {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 49ce124..4447971 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -663,17 +663,20 @@
             if (DBG) Slog.d(TAG, getName() + message.toString());
             switch (message.what) {
                 case WifiMonitor.AP_STA_CONNECTED_EVENT:
-                    String address = (String) message.obj;
-                    mGroup.addClient(address);
-                    updateDeviceStatus(address, Status.CONNECTED);
+                    //After a GO setup, STA connected event comes with interface address
+                    String interfaceAddress = (String) message.obj;
+                    String deviceAddress = getDeviceAddress(interfaceAddress);
+                    mGroup.addClient(deviceAddress);
+                    updateDeviceStatus(deviceAddress, Status.CONNECTED);
                     if (DBG) Slog.d(TAG, getName() + " ap sta connected");
                     sendP2pPeersChangedBroadcast();
                     break;
                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
-                    address = (String) message.obj;
-                    updateDeviceStatus(address, Status.AVAILABLE);
-                    if (mGroup.removeClient(address)) {
-                        if (DBG) Slog.d(TAG, "Removed client " + address);
+                    interfaceAddress = (String) message.obj;
+                    deviceAddress = getDeviceAddress(interfaceAddress);
+                    updateDeviceStatus(deviceAddress, Status.AVAILABLE);
+                    if (mGroup.removeClient(deviceAddress)) {
+                        if (DBG) Slog.d(TAG, "Removed client " + deviceAddress);
                         if (mGroup.isClientListEmpty()) {
                             Slog.d(TAG, "Client list empty, killing p2p connection");
                             sendMessage(WifiP2pManager.REMOVE_GROUP);
@@ -682,7 +685,7 @@
                             sendP2pPeersChangedBroadcast();
                         }
                     } else {
-                        if (DBG) Slog.d(TAG, "Failed to remove client " + address);
+                        if (DBG) Slog.d(TAG, "Failed to remove client " + deviceAddress);
                         for (WifiP2pDevice c : mGroup.getClientList()) {
                             if (DBG) Slog.d(TAG,"client " + c.deviceAddress);
                         }
@@ -1005,12 +1008,20 @@
 
     private void updateDeviceStatus(String deviceAddress, Status status) {
         for (WifiP2pDevice d : mPeers.getDeviceList()) {
-           // TODO: fix later
-           // if (d.deviceAddress.equals(deviceAddress)) {
-            if (d.deviceAddress.startsWith(deviceAddress.substring(0, 8))) {
+            if (d.deviceAddress.equals(deviceAddress)) {
                 d.status = status;
             }
         }
     }
+
+    private String getDeviceAddress(String interfaceAddress) {
+        for (WifiP2pDevice d : mPeers.getDeviceList()) {
+            if (interfaceAddress.equals(WifiNative.p2pGetInterfaceAddress(d.deviceAddress))) {
+                return d.deviceAddress;
+            }
+        }
+        return null;
+    }
+
     }
 }