Merge "DO NOT MERGE Remove wifistatetracker lock access in BroadcastReceiver" into gingerbread
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2dd5819..5998074 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -367,7 +367,8 @@
             }
 
             Map map = null;
-            if (prefsFile.exists() && prefsFile.canRead()) {
+            FileStatus stat = new FileStatus();
+            if (FileUtils.getFileStatus(prefsFile.getPath(), stat) && prefsFile.canRead()) {
                 try {
                     FileInputStream str = new FileInputStream(prefsFile);
                     map = XmlUtils.readMapXml(str);
@@ -380,7 +381,7 @@
                     Log.w(TAG, "getSharedPreferences", e);
                 }
             }
-            sp.replace(map);
+            sp.replace(map, stat);
         }
         return sp;
     }
@@ -2768,12 +2769,16 @@
             }
         }
 
-        public void replace(Map newContents) {
+        /* package */ void replace(Map newContents, FileStatus stat) {
             synchronized (this) {
                 mLoaded = true;
                 if (newContents != null) {
                     mMap = newContents;
                 }
+                if (stat != null) {
+                    mStatTimestamp = stat.mtime;
+                    mStatSize = stat.size;
+                }
             }
         }
 
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 32ff3b3..8c55bf3 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -220,25 +220,47 @@
      * </p>
      * 
      *  <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
-     *  A three dimensional vector indicating the direction and magnitude of gravity.  Units
-     *  are m/s^2.  The coordinate system is the same as is used by the acceleration sensor.
+     *  <p>A three dimensional vector indicating the direction and magnitude of gravity.  Units
+     *  are m/s^2. The coordinate system is the same as is used by the acceleration sensor.</p>
+     *  <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be identical
+     *  to that of the accelerometer.</p>
      *
      *  <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
      *  A three dimensional vector indicating acceleration along each device axis, not including
      *  gravity.  All values have units of m/s^2.  The coordinate system is the same as is used by the
-     * acceleration sensor.
+     *  acceleration sensor.
+     *  <p>The output of the accelerometer, gravity and  linear-acceleration sensors must obey the
+     *  following relation:</p>
+     *   <p><ul>acceleration = gravity + linear-acceleration</ul></p>
      *
      *  <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
-     *  The rotation vector represents the orientation of the device as a combination of an angle
-     *  and an axis, in which the device has rotated through an angle theta around an axis
-     *  &lt;x, y, z>. The three elements of the rotation vector are
-     *  &lt;x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>, such that the magnitude of the rotation
-     *  vector is equal to sin(theta/2), and the direction of the rotation vector is equal to the
-     *  direction of the axis of rotation. The three elements of the rotation vector are equal to
-     *  the last three components of a unit quaternion
-     *  &lt;cos(theta/2), x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>.  Elements of the rotation
-     *  vector are unitless.  The x,y, and z axis are defined in the same way as the acceleration
-     *  sensor.
+     *  <p>The rotation vector represents the orientation of the device as a combination of an <i>angle</i>
+     *  and an <i>axis</i>, in which the device has rotated through an angle &#952 around an axis
+     *  &lt;x, y, z>.</p>
+     *  <p>The three elements of the rotation vector are
+     *  &lt;x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>, such that the magnitude of the rotation
+     *  vector is equal to sin(&#952/2), and the direction of the rotation vector is equal to the
+     *  direction of the axis of rotation.</p>
+     *  </p>The three elements of the rotation vector are equal to
+     *  the last three components of a <b>unit</b> quaternion
+     *  &lt;cos(&#952/2), x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>.</p>
+     *  <p>Elements of the rotation vector are unitless.
+     *  The x,y, and z axis are defined in the same way as the acceleration
+     *  sensor.</p>
+     * <ul>
+     * <p>
+     * values[0]: x*sin(&#952/2)
+     * </p>
+     * <p>
+     * values[1]: y*sin(&#952/2)
+     * </p>
+     * <p>
+     * values[2]: z*sin(&#952/2)
+     * </p>
+     * <p>
+     * values[3]: cos(&#952/2) <i>(optional: only if value.length = 4)</i>
+     * </p>
+     * </ul>
      *
      * <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
      * Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index c178aee..1b799ae 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1938,13 +1938,18 @@
      *  @param R an array of floats in which to store the rotation matrix
      */
     public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) {
-        float q0 = (float)Math.sqrt(1 - rotationVector[0]*rotationVector[0] -
-                                    rotationVector[1]*rotationVector[1] -
-                                    rotationVector[2]*rotationVector[2]);
+
+        float q0;
         float q1 = rotationVector[0];
         float q2 = rotationVector[1];
         float q3 = rotationVector[2];
 
+        if (rotationVector.length == 4) {
+            q0 = rotationVector[3];
+        } else {
+            q0 = (float)Math.sqrt(1 - q1*q1 - q2*q2 - q3*q3);
+        }
+
         float sq_q1 = 2 * q1 * q1;
         float sq_q2 = 2 * q2 * q2;
         float sq_q3 = 2 * q3 * q3;
@@ -1995,10 +2000,12 @@
      *  @param Q an array of floats in which to store the computed quaternion
      */
     public static void getQuaternionFromVector(float[] Q, float[] rv) {
-        float w = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
-        //In this case, the w component of the quaternion is known to be a positive number
-
-        Q[0] = w;
+        if (rv.length == 4) {
+            Q[0] = rv[3];
+        } else {
+            //In this case, the w component of the quaternion is known to be a positive number
+            Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+        }
         Q[1] = rv[0];
         Q[2] = rv[1];
         Q[3] = rv[2];
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index da72f9c..5c6aa99 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -29,7 +29,7 @@
 
 GravitySensor::GravitySensor(sensor_t const* list, size_t count)
     : mSensorDevice(SensorDevice::getInstance()),
-      mEnabled(false), mAccTime(0),
+      mAccTime(0),
       mLowPass(M_SQRT1_2, 1.5f),
       mX(mLowPass), mY(mLowPass), mZ(mLowPass)
 
@@ -71,15 +71,9 @@
     }
     return false;
 }
-
-bool GravitySensor::isEnabled() const {
-    return mEnabled;
-}
-
 status_t GravitySensor::activate(void* ident, bool enabled) {
     status_t err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
     if (err == NO_ERROR) {
-        mEnabled = enabled;
         if (enabled) {
             mAccTime = 0;
         }
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index ff3bea7..decfbb8 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -33,7 +33,6 @@
 class GravitySensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     Sensor mAccelerometer;
-    bool mEnabled;
     double mAccTime;
 
     SecondOrderLowPassFilter mLowPass;
@@ -43,7 +42,6 @@
     GravitySensor(sensor_t const* list, size_t count);
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
-    virtual bool isEnabled() const;
     virtual status_t activate(void* ident, bool enabled);
     virtual status_t setDelay(void* ident, int handle, int64_t ns);
     virtual Sensor getSensor() const;
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
index 2dc12dc..9425a92 100644
--- a/services/sensorservice/LinearAccelerationSensor.cpp
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -53,10 +53,6 @@
     return result;
 }
 
-bool LinearAccelerationSensor::isEnabled() const {
-    return mGravitySensor.isEnabled();
-}
-
 status_t LinearAccelerationSensor::activate(void* ident, bool enabled) {
     return mGravitySensor.activate(ident, enabled);
 }
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
index ee918ce..c577086a 100644
--- a/services/sensorservice/LinearAccelerationSensor.h
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -40,7 +40,6 @@
             const sensors_event_t& event);
 public:
     LinearAccelerationSensor(sensor_t const* list, size_t count);
-    virtual bool isEnabled() const;
     virtual status_t activate(void* ident, bool enabled);
     virtual status_t setDelay(void* ident, int handle, int64_t ns);
     virtual Sensor getSensor() const;
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index eecf260..418e7f8 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -34,7 +34,6 @@
 
 RotationVectorSensor::RotationVectorSensor(sensor_t const* list, size_t count)
     : mSensorDevice(SensorDevice::getInstance()),
-      mEnabled(false),
       mALowPass(M_SQRT1_2, 5.0f),
       mAX(mALowPass), mAY(mALowPass), mAZ(mALowPass),
       mMLowPass(M_SQRT1_2, 2.5f),
@@ -125,6 +124,7 @@
         outEvent->data[0] = qx;
         outEvent->data[1] = qy;
         outEvent->data[2] = qz;
+        outEvent->data[3] = qw;
         outEvent->sensor = '_rov';
         outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
         return true;
@@ -132,19 +132,12 @@
     return false;
 }
 
-bool RotationVectorSensor::isEnabled() const {
-    return mEnabled;
-}
-
 status_t RotationVectorSensor::activate(void* ident, bool enabled) {
-    if (mEnabled != enabled) {
-        mSensorDevice.activate(this, mAcc.getHandle(), enabled);
-        mSensorDevice.activate(this, mMag.getHandle(), enabled);
-        mEnabled = enabled;
-        if (enabled) {
-            mMagTime = 0;
-            mAccTime = 0;
-        }
+    mSensorDevice.activate(this, mAcc.getHandle(), enabled);
+    mSensorDevice.activate(this, mMag.getHandle(), enabled);
+    if (enabled) {
+        mMagTime = 0;
+        mAccTime = 0;
     }
     return NO_ERROR;
 }
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index e7f28c9..b7c9512 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -34,7 +34,6 @@
     SensorDevice& mSensorDevice;
     Sensor mAcc;
     Sensor mMag;
-    bool mEnabled;
     float mMagData[3];
     double mAccTime;
     double mMagTime;
@@ -47,7 +46,6 @@
     RotationVectorSensor(sensor_t const* list, size_t count);
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
-    virtual bool isEnabled() const;
     virtual status_t activate(void* ident, bool enabled);
     virtual status_t setDelay(void* ident, int handle, int64_t ns);
     virtual Sensor getSensor() const;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 73f85ba..f192913 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -137,9 +137,8 @@
 
     Mutex::Autolock _l(mLock);
     for (size_t i=0 ; i<size_t(count) ; i++) {
-        snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d / %d\n",
+        snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d\n",
                 list[i].handle,
-                mActivationCount.valueFor(list[i].handle).count,
                 mActivationCount.valueFor(list[i].handle).rates.size());
         result.append(buffer);
     }
@@ -167,22 +166,25 @@
     bool actuateHardware = false;
 
     Info& info( mActivationCount.editValueFor(handle) );
-    int32_t& count(info.count);
     if (enabled) {
-        if (android_atomic_inc(&count) == 0) {
-            actuateHardware = true;
-        }
         Mutex::Autolock _l(mLock);
         if (info.rates.indexOfKey(ident) < 0) {
             info.rates.add(ident, DEFAULT_EVENTS_PERIOD);
+            actuateHardware = true;
+        } else {
+            // sensor was already activated for this ident
         }
     } else {
-        if (android_atomic_dec(&count) == 1) {
-            actuateHardware = true;
-        }
         Mutex::Autolock _l(mLock);
-        info.rates.removeItem(ident);
+        if (info.rates.removeItem(ident) >= 0) {
+            if (info.rates.size() == 0) {
+                actuateHardware = true;
+            }
+        } else {
+            // sensor wasn't enabled for this ident
+        }
     }
+
     if (actuateHardware) {
         err = mSensorDevice->activate(mSensorDevice, handle, enabled);
         if (enabled) {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 63ecbcd..c19b2ce 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -40,8 +40,7 @@
     Mutex mLock; // protect mActivationCount[].rates
     // fixed-size array after construction
     struct Info {
-        Info() : count(0) { }
-        int32_t count;
+        Info() { }
         KeyedVector<void*, nsecs_t> rates;
     };
     DefaultKeyedVector<int, Info> mActivationCount;
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 93d23d9..be8eaff 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -32,7 +32,7 @@
 
 HardwareSensor::HardwareSensor(const sensor_t& sensor)
     : mSensorDevice(SensorDevice::getInstance()),
-      mSensor(&sensor), mEnabled(false)
+      mSensor(&sensor)
 {
     LOGI("%s", sensor.name);
 }
@@ -46,15 +46,8 @@
     return true;
 }
 
-bool HardwareSensor::isEnabled() const {
-    return mEnabled;
-}
-
-status_t HardwareSensor::activate(void* ident,bool enabled) {
-    status_t err = mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
-    if (err == NO_ERROR)
-        mEnabled = enabled;
-    return err;
+status_t HardwareSensor::activate(void* ident, bool enabled) {
+    return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
 }
 
 status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index eebd563..084f2f5 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -38,7 +38,6 @@
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event) = 0;
 
-    virtual bool isEnabled() const = 0;
     virtual status_t activate(void* ident, bool enabled) = 0;
     virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
     virtual Sensor getSensor() const = 0;
@@ -51,7 +50,6 @@
 {
     SensorDevice& mSensorDevice;
     Sensor mSensor;
-    bool mEnabled;
 
 public:
     HardwareSensor(const sensor_t& sensor);
@@ -61,7 +59,6 @@
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
 
-    virtual bool isEnabled() const;
     virtual status_t activate(void* ident, bool enabled);
     virtual status_t setDelay(void* ident, int handle, int64_t ns);
     virtual Sensor getSensor() const;
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index f7506c6..857d105 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,12 +20,13 @@
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.provider.ContactsContract.PhoneLookup;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
-import static android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.telephony.TelephonyManager;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.RawContacts;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Log;
 
 
@@ -164,33 +165,17 @@
                     }
                 }
 
-                // Look for the person ID.
-
-                // TODO: This is pretty ugly now, see bug 2269240 for
-                // more details. The column to use depends upon the type of URL,
-                // for content://com.android.contacts/data/phones the "contact_id"
-                // column is used. For content/com.andriod.contacts/phone_lookup"
-                // the "_ID" column is used. If it is neither we leave columnIndex
-                // at -1 and no person ID will be available.
-
-                columnIndex = -1;
-                String url = contactRef.toString();
-                if (url.startsWith("content://com.android.contacts/data/phones")) {
-                    if (VDBG) Log.v(TAG,
-                        "URL path starts with 'data/phones' using RawContacts.CONTACT_ID");
-                    columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID);
-                } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
-                    if (VDBG) Log.v(TAG,
-                        "URL path starts with 'phone_lookup' using PhoneLookup._ID");
-                    columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
-                } else {
-                    Log.e(TAG, "Bad contact URL '" + url + "'");
-                }
-
+                // Look for the person_id.
+                columnIndex = getColumnIndexForPersonId(contactRef, cursor);
                 if (columnIndex != -1) {
                     info.person_id = cursor.getLong(columnIndex);
+                    if (VDBG) Log.v(TAG, "==> got info.person_id: " + info.person_id);
                 } else {
-                    Log.e(TAG, "person_id column missing for " + contactRef);
+                    // No valid columnIndex, so we can't look up person_id.
+                    Log.w(TAG, "Couldn't find person_id column for " + contactRef);
+                    // Watch out: this means that anything that depends on
+                    // person_id will be broken (like contact photo lookups in
+                    // the in-call UI, for example.)
                 }
 
                 // look for the custom ringtone, create from the string stored
@@ -404,30 +389,120 @@
     }
 
     /**
+     * Returns the column index to use to find the "person_id" field in
+     * the specified cursor, based on the contact URI that was originally
+     * queried.
+     *
+     * This is a helper function for the getCallerInfo() method that takes
+     * a Cursor.  Looking up the person_id is nontrivial (compared to all
+     * the other CallerInfo fields) since the column we need to use
+     * depends on what query we originally ran.
+     *
+     * Watch out: be sure to not do any database access in this method, since
+     * it's run from the UI thread (see comments below for more info.)
+     *
+     * @return the columnIndex to use (with cursor.getLong()) to get the
+     * person_id, or -1 if we couldn't figure out what colum to use.
+     *
+     * TODO: Add a unittest for this method.  (This is a little tricky to
+     * test, since we'll need a live contacts database to test against,
+     * preloaded with at least some phone numbers and SIP addresses.  And
+     * we'll probably have to hardcode the column indexes we expect, so
+     * the test might break whenever the contacts schema changes.  But we
+     * can at least make sure we handle all the URI patterns we claim to,
+     * and that the mime types match what we expect...)
+     */
+    private static int getColumnIndexForPersonId(Uri contactRef, Cursor cursor) {
+        // TODO: This is pretty ugly now, see bug 2269240 for
+        // more details. The column to use depends upon the type of URL:
+        // - content://com.android.contacts/data/phones ==> use the "contact_id" column
+        // - content://com.android.contacts/phone_lookup ==> use the "_ID" column
+        // - content://com.android.contacts/data ==> use the "contact_id" column
+        // If it's none of the above, we leave columnIndex=-1 which means
+        // that the person_id field will be left unset.
+        //
+        // The logic here *used* to be based on the mime type of contactRef
+        // (for example Phone.CONTENT_ITEM_TYPE would tell us to use the
+        // RawContacts.CONTACT_ID column).  But looking up the mime type requires
+        // a call to context.getContentResolver().getType(contactRef), which
+        // isn't safe to do from the UI thread since it can cause an ANR if
+        // the contacts provider is slow or blocked (like during a sync.)
+        //
+        // So instead, figure out the column to use for person_id by just
+        // looking at the URI itself.
+
+        if (VDBG) Log.v(TAG, "- getColumnIndexForPersonId: contactRef URI = '"
+                        + contactRef + "'...");
+        // Warning: Do not enable the following logging (due to ANR risk.)
+        // if (VDBG) Log.v(TAG, "- MIME type: "
+        //                 + context.getContentResolver().getType(contactRef));
+
+        String url = contactRef.toString();
+        String columnName = null;
+        if (url.startsWith("content://com.android.contacts/data/phones")) {
+            // Direct lookup in the Phone table.
+            // MIME type: Phone.CONTENT_ITEM_TYPE (= "vnd.android.cursor.item/phone_v2")
+            if (VDBG) Log.v(TAG, "'data/phones' URI; using RawContacts.CONTACT_ID");
+            columnName = RawContacts.CONTACT_ID;
+        } else if (url.startsWith("content://com.android.contacts/data")) {
+            // Direct lookup in the Data table.
+            // MIME type: Data.CONTENT_TYPE (= "vnd.android.cursor.dir/data")
+            if (VDBG) Log.v(TAG, "'data' URI; using Data.CONTACT_ID");
+            // (Note Data.CONTACT_ID and RawContacts.CONTACT_ID are equivalent.)
+            columnName = Data.CONTACT_ID;
+        } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
+            // Lookup in the PhoneLookup table, which provides "fuzzy matching"
+            // for phone numbers.
+            // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
+            if (VDBG) Log.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
+            columnName = PhoneLookup._ID;
+        } else {
+            Log.w(TAG, "Unexpected prefix for contactRef '" + url + "'");
+        }
+        int columnIndex = (columnName != null) ? cursor.getColumnIndex(columnName) : -1;
+        if (VDBG) Log.v(TAG, "==> Using column '" + columnName
+                        + "' (columnIndex = " + columnIndex + ") for person_id lookup...");
+        return columnIndex;
+    }
+
+    /**
      * @return a string debug representation of this instance.
      */
     public String toString() {
-        return new StringBuilder(384)
-                .append("\nname: " + /*name*/ "nnnnnn")
-                .append("\nphoneNumber: " + /*phoneNumber*/ "xxxxxxx")
-                .append("\ncnapName: " + cnapName)
-                .append("\nnumberPresentation: " + numberPresentation)
-                .append("\nnamePresentation: " + namePresentation)
-                .append("\ncontactExits: " + contactExists)
-                .append("\nphoneLabel: " + phoneLabel)
-                .append("\nnumberType: " + numberType)
-                .append("\nnumberLabel: " + numberLabel)
-                .append("\nphotoResource: " + photoResource)
-                .append("\nperson_id: " + person_id)
-                .append("\nneedUpdate: " + needUpdate)
-                .append("\ncontactRefUri: " + /*contactRefUri*/ "xxxxxxx")
-                .append("\ncontactRingtoneUri: " + /*contactRefUri*/ "xxxxxxx")
-                .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
-                .append("\ncachedPhoto: " + cachedPhoto)
-                .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
-                .append("\nemergency: " + mIsEmergency)
-                .append("\nvoicemail " + mIsVoiceMail)
-                .append("\ncontactExists " + contactExists)
-                .toString();
+        // Warning: never check in this file with VERBOSE_DEBUG = true
+        // because that will result in PII in the system log.
+        final boolean VERBOSE_DEBUG = false;
+
+        if (VERBOSE_DEBUG) {
+            return new StringBuilder(384)
+                    .append("\nname: " + name)
+                    .append("\nphoneNumber: " + phoneNumber)
+                    .append("\ncnapName: " + cnapName)
+                    .append("\nnumberPresentation: " + numberPresentation)
+                    .append("\nnamePresentation: " + namePresentation)
+                    .append("\ncontactExits: " + contactExists)
+                    .append("\nphoneLabel: " + phoneLabel)
+                    .append("\nnumberType: " + numberType)
+                    .append("\nnumberLabel: " + numberLabel)
+                    .append("\nphotoResource: " + photoResource)
+                    .append("\nperson_id: " + person_id)
+                    .append("\nneedUpdate: " + needUpdate)
+                    .append("\ncontactRefUri: " + contactRefUri)
+                    .append("\ncontactRingtoneUri: " + contactRefUri)
+                    .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+                    .append("\ncachedPhoto: " + cachedPhoto)
+                    .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+                    .append("\nemergency: " + mIsEmergency)
+                    .append("\nvoicemail " + mIsVoiceMail)
+                    .append("\ncontactExists " + contactExists)
+                    .toString();
+        } else {
+            return new StringBuilder(128)
+                    .append("CallerInfo { ")
+                    .append("name " + ((name == null) ? "null" : "non-null"))
+                    .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
+                    .append(" }")
+                    .toString();
+        }
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 818605a..5cf25313 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -656,12 +656,6 @@
             @Override
             protected void onError(DisconnectCause cause) {
                 if (DEBUG) Log.d(LOG_TAG, "SIP error: " + cause);
-                if (mSipAudioCall.isInCall()
-                        && (cause != DisconnectCause.LOST_SIGNAL)) {
-                    // Don't end the call when in a call.
-                    return;
-                }
-
                 onCallEnded(cause);
             }
         };
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 2fbaee2..30ddfb5 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -527,11 +527,14 @@
         }
 
         public void answerCall(String sessionDescription, int timeout) {
-            try {
-                processCommand(new MakeCallCommand(mPeerProfile,
-                        sessionDescription, timeout));
-            } catch (SipException e) {
-                onError(e);
+            synchronized (SipSessionGroup.this) {
+                if (mPeerProfile == null) return;
+                try {
+                    processCommand(new MakeCallCommand(mPeerProfile,
+                            sessionDescription, timeout));
+                } catch (SipException e) {
+                    onError(e);
+                }
             }
         }
 
@@ -540,14 +543,11 @@
         }
 
         public void changeCall(String sessionDescription, int timeout) {
-            doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
-                    timeout));
-        }
-
-        public void changeCallWithTimeout(
-                String sessionDescription, int timeout) {
-            doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
-                    timeout));
+            synchronized (SipSessionGroup.this) {
+                if (mPeerProfile == null) return;
+                doCommandAsync(new MakeCallCommand(mPeerProfile,
+                        sessionDescription, timeout));
+            }
         }
 
         public void register(int duration) {
@@ -1163,11 +1163,6 @@
             mProxy.onCallEstablished(this, mPeerSessionDescription);
         }
 
-        private void fallbackToPreviousInCall(int errorCode, String message) {
-            mState = SipSession.State.IN_CALL;
-            mProxy.onCallChangeFailed(this, errorCode, message);
-        }
-
         private void endCallNormally() {
             reset();
             mProxy.onCallEnded(this);
@@ -1191,12 +1186,7 @@
                     onRegistrationFailed(errorCode, message);
                     break;
                 default:
-                    if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
-                            && mInCall) {
-                        fallbackToPreviousInCall(errorCode, message);
-                    } else {
-                        endCallOnError(errorCode, message);
-                    }
+                    endCallOnError(errorCode, message);
             }
         }