Merge "Add lost frame handling in AudioSource" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index f1a383f..4dd0909 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -77549,6 +77549,17 @@
  visibility="public"
 >
 </method>
+<method name="getMinDelay"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getName"
  return="java.lang.String"
  abstract="false"
@@ -77847,6 +77858,21 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="getAltitude"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="p0" type="float">
+</parameter>
+<parameter name="p" type="float">
+</parameter>
+</method>
 <method name="getDefaultSensor"
  return="android.hardware.Sensor"
  abstract="false"
@@ -78426,6 +78452,17 @@
  visibility="public"
 >
 </field>
+<field name="PRESSURE_STANDARD_ATMOSPHERE"
+ type="float"
+ transient="false"
+ volatile="false"
+ value="1013.25f"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="RAW_DATA_INDEX"
  type="int"
  transient="false"
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1fe85e6..9a55a6f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -37,6 +37,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.ServiceManager;
+import android.os.StrictMode;
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
@@ -1056,8 +1057,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             IBinder app = data.readStrongBinder();
             int violationMask = data.readInt();
-            ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
-            handleApplicationStrictModeViolation(app, violationMask, ci);
+            StrictMode.ViolationInfo info = new StrictMode.ViolationInfo(data);
+            handleApplicationStrictModeViolation(app, violationMask, info);
             reply.writeNoException();
             return true;
         }
@@ -2571,14 +2572,14 @@
 
     public void handleApplicationStrictModeViolation(IBinder app,
             int violationMask,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
+            StrictMode.ViolationInfo info) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(app);
         data.writeInt(violationMask);
-        crashInfo.writeToParcel(data, 0);
+        info.writeToParcel(data, 0);
         mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0);
         reply.readException();
         reply.recycle();
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 30815c3..8f940d5 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -24,6 +24,7 @@
 import android.content.pm.ResolveInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Printer;
@@ -74,18 +75,15 @@
     public static final int TYPE_BATTERY = 3;
 
     /**
-     * An error report about a StrictMode violation.
-     */
-    public static final int TYPE_STRICT_MODE_VIOLATION = 4;
-
-    /**
-     * An error report about a StrictMode violation.
+     * A report from a user to a developer about a running service that the
+     * user doesn't think should be running.
      */
     public static final int TYPE_RUNNING_SERVICE = 5;
 
     /**
      * Type of this report. Can be one of {@link #TYPE_NONE},
-     * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}.
+     * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, {@link #TYPE_BATTERY},
+     * or {@link #TYPE_RUNNING_SERVICE}.
      */
     public int type;
 
@@ -133,7 +131,7 @@
      * of BatteryInfo; otherwise null.
      */
     public BatteryInfo batteryInfo;
-    
+
     /**
      * If this report is of type {@link #TYPE_RUNNING_SERVICE}, contains an instance
      * of RunningServiceInfo; otherwise null.
@@ -278,10 +276,6 @@
 
     /**
      * Describes an application crash.
-     *
-     * <p>This is also used to marshal around stack traces of ANRs and
-     * StrictMode violations which aren't necessarily crashes, but have
-     * a lot in common.
      */
     public static class CrashInfo {
         /**
@@ -320,12 +314,6 @@
         public String stackTrace;
 
         /**
-         * For StrictMode violations, the wall time duration of the
-         * violation, when known.
-         */
-        public long durationMillis = -1;
-
-        /**
          * Create an uninitialized instance of CrashInfo.
          */
         public CrashInfo() {
@@ -368,7 +356,6 @@
             throwMethodName = in.readString();
             throwLineNumber = in.readInt();
             stackTrace = in.readString();
-            durationMillis = in.readLong();
         }
 
         /**
@@ -382,7 +369,6 @@
             dest.writeString(throwMethodName);
             dest.writeInt(throwLineNumber);
             dest.writeString(stackTrace);
-            dest.writeLong(durationMillis);
         }
 
         /**
@@ -396,9 +382,6 @@
             pw.println(prefix + "throwMethodName: " + throwMethodName);
             pw.println(prefix + "throwLineNumber: " + throwLineNumber);
             pw.println(prefix + "stackTrace: " + stackTrace);
-            if (durationMillis != -1) {
-                pw.println(prefix + "durationMillis: " + durationMillis);
-            }
         }
     }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 20c9a80..81b28b9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -19,10 +19,10 @@
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IIntentSender;
-import android.content.IIntentReceiver;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -31,14 +31,15 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Debug;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
-import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.StrictMode;
 
 import java.util.List;
 
@@ -260,7 +261,7 @@
     // bit violated and penalty bits to be executed by the
     // ActivityManagerService remaining set.
     public void handleApplicationStrictModeViolation(IBinder app, int violationMask,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
+            StrictMode.ViolationInfo crashInfo) throws RemoteException;
 
     /*
      * This will deliver the specified signal to all the persistent processes. Currently only 
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index b7a750b..00063af 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -403,7 +403,7 @@
      *
      * <p class="caution">Note that the system calls this on your
      * service's main thread.  A service's main thread is the same
-     * thread where UI operations place for Activities running in the
+     * thread where UI operations take place for Activities running in the
      * same process.  You should always avoid stalling the main
      * thread's event loop.  When doing long-running operations,
      * network calls, or heavy disk I/O, you should kick off a new
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7951a30..aecdcb3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1206,6 +1206,8 @@
      * for management of input methods.
      * <dt> {@link #UI_MODE_SERVICE} ("uimode")
      * <dd> An {@link android.app.UiModeManager} for controlling UI modes.
+     * <dt> {@link #DOWNLOAD_SERVICE} ("download")
+     * <dd> A {@link android.net.DownloadManager} for requesting HTTP downloads
      * </dl>
      * 
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -1253,6 +1255,8 @@
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
      * @see android.app.UiModeManager
+     * @see #DOWNLOAD_SERVICE
+     * @see android.net.DownloadManager
      */
     public abstract Object getSystemService(String name);
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 73c4011..0b35d8b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -587,7 +587,7 @@
      * location from the apk location at the given file path.
      * @param packageFilePath file location of the apk
      * @param flags Special parse flags
-     * @return PackageLite object with package information.
+     * @return PackageLite object with package information or null on failure.
      */
     public static PackageLite parsePackageLite(String packageFilePath, int flags) {
         XmlResourceParser parser = null;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 3490ac0..b49a409 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -92,6 +92,7 @@
     private float   mMaxRange;
     private float   mResolution;
     private float   mPower;
+    private int     mMinDelay;
     private int     mLegacyType;
 
 
@@ -147,6 +148,15 @@
         return mPower;
     }
 
+    /**
+     * @return the minimum delay allowed between two events in microsecond
+     * or zero if this sensor only returns a value when the data it's measuring
+     * changes.
+     */
+    public int getMinDelay() {
+        return mMinDelay;
+    }
+
     int getHandle() {
         return mHandle;
     }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index e6750e6..f6d237a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -268,6 +268,10 @@
     public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
 
 
+    /** Standard atmosphere, or average sea-level pressure in hPa (millibar) */
+    public static final float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f;
+
+
     /** Maximum luminance of sunlight in lux */
     public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
     /** luminance of sunlight in lux */
@@ -573,11 +577,11 @@
                     // which won't get the rotated values
                     try {
                         sRotation = sWindowManager.watchRotation(
-                            new IRotationWatcher.Stub() {
-                                public void onRotationChanged(int rotation) {
-                                    SensorManager.this.onRotationChanged(rotation);
+                                new IRotationWatcher.Stub() {
+                                    public void onRotationChanged(int rotation) {
+                                        SensorManager.this.onRotationChanged(rotation);
+                                    }
                                 }
-                            }
                         );
                     } catch (RemoteException e) {
                     }
@@ -638,7 +642,7 @@
                     break;
                 case Sensor.TYPE_ORIENTATION:
                     result |= SensorManager.SENSOR_ORIENTATION |
-                                    SensorManager.SENSOR_ORIENTATION_RAW;
+                    SensorManager.SENSOR_ORIENTATION_RAW;
                     break;
             }
         }
@@ -935,7 +939,8 @@
      *        received faster or slower than the specified rate. Usually events
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
-     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
+     *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
+     *        or, the desired delay between events in microsecond.
      *
      * @return <code>true</code> if the sensor is supported and successfully
      *         enabled.
@@ -967,6 +972,7 @@
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
+     *        or, the desired delay between events in microsecond.
      *
      * @param handler
      *        The {@link android.os.Handler Handler} the
@@ -992,16 +998,17 @@
                 delay = 0;
                 break;
             case SENSOR_DELAY_GAME:
-                delay = 20;
+                delay = 20000;
                 break;
             case SENSOR_DELAY_UI:
-                delay = 60;
+                delay = 60000;
                 break;
             case SENSOR_DELAY_NORMAL:
-                delay = 200;
+                delay = 200000;
                 break;
             default:
-                return false;
+                delay = rate;
+                break;
         }
 
         synchronized (sListeners) {
@@ -1485,7 +1492,7 @@
      * @see #getRotationMatrix(float[], float[], float[], float[])
      * @see GeomagneticField
      */
-   public static float[] getOrientation(float[] R, float values[]) {
+    public static float[] getOrientation(float[] R, float values[]) {
         /*
          * 4x4 (length=16) case:
          *   /  R[ 0]   R[ 1]   R[ 2]   0  \
@@ -1511,8 +1518,27 @@
         return values;
     }
 
-
     /**
+     * Computes the Altitude in meters from the atmospheric pressure and the
+     * pressure at sea level.
+     * <p>
+     * Typically the atmospheric pressure is read from a
+     * {@link Sensor#TYPE_PRESSURE} sensor. The pressure at sea level must be
+     * known, usually it can be retrieved from airport databases in the
+     * vicinity.
+     * </p>
+     *
+     * @param p0 pressure at sea level
+     * @param p atmospheric pressure
+     * @return Altitude in meters
+     */
+   public static float getAltitude(float p0, float p) {
+        final float coef = 1.0f / 5.255f;
+        return 44330.0f * (1.0f - (float)Math.pow(p/p0, coef));
+    }
+
+
+   /**
      * {@hide}
      */
     public void onRotationChanged(int rotation) {
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index d4b0500..ac12e10 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -18,6 +18,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ApplicationErrorReport;
 import android.util.Log;
+import android.util.Printer;
 
 import com.android.internal.os.RuntimeInit;
 
@@ -97,9 +98,9 @@
      * via Parcel.writeNoException() (amusingly) where the caller can
      * choose how to react.
      */
-    private static final ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>> gatheredViolations =
-            new ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>>() {
-        @Override protected ArrayList<ApplicationErrorReport.CrashInfo> initialValue() {
+    private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations =
+            new ThreadLocal<ArrayList<ViolationInfo>>() {
+        @Override protected ArrayList<ViolationInfo> initialValue() {
             // Starts null to avoid unnecessary allocations when
             // checking whether there are any violations or not in
             // hasGatheredViolations() below.
@@ -240,7 +241,9 @@
             if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeDiskWriteViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         // Part of BlockGuard.Policy interface:
@@ -248,7 +251,9 @@
             if ((mPolicyMask & DISALLOW_DISK_READ) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeDiskReadViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         // Part of BlockGuard.Policy interface:
@@ -256,7 +261,9 @@
             if ((mPolicyMask & DISALLOW_NETWORK) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeNetworkViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         public void setPolicyMask(int policyMask) {
@@ -269,31 +276,70 @@
         // thread and, if so, uses it to roughly measure how long the
         // violation took.
         void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
-            e.fillInStackTrace();
-            final ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(e);
-            crashInfo.durationMillis = -1;  // unknown
-            final int savedPolicy = mPolicyMask;
+            final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
+            info.violationUptimeMillis = SystemClock.uptimeMillis();
+            handleViolationWithTimingAttempt(info);
+        }
 
+        private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
+                new ThreadLocal<ArrayList<ViolationInfo>>() {
+            @Override protected ArrayList<ViolationInfo> initialValue() {
+                return new ArrayList<ViolationInfo>();
+            }
+        };
+
+        // Attempts to fill in the provided ViolationInfo's
+        // durationMillis field if this thread has a Looper we can use
+        // to measure with.  We measure from the time of violation
+        // until the time the looper is idle again (right before
+        // the next epoll_wait)
+        void handleViolationWithTimingAttempt(final ViolationInfo info) {
             Looper looper = Looper.myLooper();
+
+            // Without a Looper, we're unable to time how long the
+            // violation takes place.  This case should be rare, as
+            // most users will care about timing violations that
+            // happen on their main UI thread.  Note that this case is
+            // also hit when a violation takes place in a Binder
+            // thread, in "gather" mode.  In this case, the duration
+            // of the violation is computed by the ultimate caller and
+            // its Looper, if any.
+            // TODO: if in gather mode, ignore Looper.myLooper() and always
+            //       go into this immediate mode?
             if (looper == null) {
-                // Without a Looper, we're unable to time how long the
-                // violation takes place.  This case should be rare,
-                // as most users will care about timing violations
-                // that happen on their main UI thread.
-                handleViolation(crashInfo, savedPolicy);
-            } else {
-                MessageQueue queue = Looper.myQueue();
-                final long violationTime = SystemClock.uptimeMillis();
-                queue.addIdleHandler(new MessageQueue.IdleHandler() {
-                        public boolean queueIdle() {
-                            long afterViolationTime = SystemClock.uptimeMillis();
-                            crashInfo.durationMillis = afterViolationTime - violationTime;
-                            handleViolation(crashInfo, savedPolicy);
-                            return false;  // remove this idle handler from the array
-                        }
-                    });
+                info.durationMillis = -1;  // unknown (redundant, already set)
+                handleViolation(info);
+                return;
             }
 
+            MessageQueue queue = Looper.myQueue();
+            final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
+            if (records.size() >= 10) {
+                // Not worth measuring.  Too many offenses in one loop.
+                return;
+            }
+            records.add(info);
+            if (records.size() > 1) {
+                // There's already been a violation this loop, so we've already
+                // registered an idle handler to process the list of violations
+                // at the end of this Looper's loop.
+                return;
+            }
+
+            queue.addIdleHandler(new MessageQueue.IdleHandler() {
+                    public boolean queueIdle() {
+                        long loopFinishTime = SystemClock.uptimeMillis();
+                        for (int n = 0; n < records.size(); ++n) {
+                            ViolationInfo v = records.get(n);
+                            v.violationNumThisLoop = n + 1;
+                            v.durationMillis =
+                                    (int) (loopFinishTime - v.violationUptimeMillis);
+                            handleViolation(v);
+                        }
+                        records.clear();
+                        return false;  // remove this idle handler from the array
+                    }
+                });
         }
 
         // Note: It's possible (even quite likely) that the
@@ -301,37 +347,35 @@
         // violation fired and now (after the violating code ran) due
         // to people who push/pop temporary policy in regions of code,
         // hence the policy being passed around.
-        void handleViolation(
-            final ApplicationErrorReport.CrashInfo crashInfo,
-            int policy) {
-            if (crashInfo.stackTrace == null) {
-                Log.d(TAG, "unexpected null stacktrace");
+        void handleViolation(final ViolationInfo info) {
+            if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) {
+                Log.wtf(TAG, "unexpected null stacktrace");
                 return;
             }
 
-            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + policy);
+            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
 
-            if ((policy & PENALTY_GATHER) != 0) {
-                ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
+            if ((info.policy & PENALTY_GATHER) != 0) {
+                ArrayList<ViolationInfo> violations = gatheredViolations.get();
                 if (violations == null) {
-                    violations = new ArrayList<ApplicationErrorReport.CrashInfo>(1);
+                    violations = new ArrayList<ViolationInfo>(1);
                     gatheredViolations.set(violations);
                 } else if (violations.size() >= 5) {
                     // Too many.  In a loop or something?  Don't gather them all.
                     return;
                 }
-                for (ApplicationErrorReport.CrashInfo previous : violations) {
-                    if (crashInfo.stackTrace.equals(previous.stackTrace)) {
+                for (ViolationInfo previous : violations) {
+                    if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) {
                         // Duplicate. Don't log.
                         return;
                     }
                 }
-                violations.add(crashInfo);
+                violations.add(info);
                 return;
             }
 
             // Not perfect, but fast and good enough for dup suppression.
-            Integer crashFingerprint = crashInfo.stackTrace.hashCode();
+            Integer crashFingerprint = info.crashInfo.stackTrace.hashCode();
             long lastViolationTime = 0;
             if (mLastViolationTime.containsKey(crashFingerprint)) {
                 lastViolationTime = mLastViolationTime.get(crashFingerprint);
@@ -341,13 +385,13 @@
             long timeSinceLastViolationMillis = lastViolationTime == 0 ?
                     Long.MAX_VALUE : (now - lastViolationTime);
 
-            if ((policy & PENALTY_LOG) != 0 &&
+            if ((info.policy & PENALTY_LOG) != 0 &&
                 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
-                if (crashInfo.durationMillis != -1) {
+                if (info.durationMillis != -1) {
                     Log.d(TAG, "StrictMode policy violation; ~duration=" +
-                          crashInfo.durationMillis + " ms: " + crashInfo.stackTrace);
+                          info.durationMillis + " ms: " + info.crashInfo.stackTrace);
                 } else {
-                    Log.d(TAG, "StrictMode policy violation: " + crashInfo.stackTrace);
+                    Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace);
                 }
             }
 
@@ -355,20 +399,20 @@
             // subset of the original StrictMode policy bitmask, with
             // only the bit violated and penalty bits to be executed
             // by the ActivityManagerService remaining set.
-            int violationMask = 0;
+            int violationMaskSubset = 0;
 
-            if ((policy & PENALTY_DIALOG) != 0 &&
+            if ((info.policy & PENALTY_DIALOG) != 0 &&
                 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
-                violationMask |= PENALTY_DIALOG;
+                violationMaskSubset |= PENALTY_DIALOG;
             }
 
-            if ((policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
-                violationMask |= PENALTY_DROPBOX;
+            if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
+                violationMaskSubset |= PENALTY_DROPBOX;
             }
 
-            if (violationMask != 0) {
-                int violationBit = parseViolationFromMessage(crashInfo.exceptionMessage);
-                violationMask |= violationBit;
+            if (violationMaskSubset != 0) {
+                int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
+                violationMaskSubset |= violationBit;
                 final int savedPolicy = getThreadBlockingPolicy();
                 try {
                     // First, remove any policy before we call into the Activity Manager,
@@ -379,8 +423,8 @@
 
                     ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
                         RuntimeInit.getApplicationObject(),
-                        violationMask,
-                        crashInfo);
+                        violationMaskSubset,
+                        info);
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
                 } finally {
@@ -389,7 +433,7 @@
                 }
             }
 
-            if ((policy & PENALTY_DEATH) != 0) {
+            if ((info.policy & PENALTY_DEATH) != 0) {
                 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
                 Process.killProcess(Process.myPid());
                 System.exit(10);
@@ -417,7 +461,7 @@
      * Called from Parcel.writeNoException()
      */
     /* package */ static void writeGatheredViolationsToParcel(Parcel p) {
-        ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
+        ArrayList<ViolationInfo> violations = gatheredViolations.get();
         if (violations == null) {
             p.writeInt(0);
         } else {
@@ -439,35 +483,21 @@
      */
     /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
         // Our own stack trace to append
-        Exception e = new LogStackTrace();
         StringWriter sw = new StringWriter();
-        e.printStackTrace(new PrintWriter(sw));
+        new LogStackTrace().printStackTrace(new PrintWriter(sw));
         String ourStack = sw.toString();
 
         int policyMask = getThreadBlockingPolicy();
+        boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
 
         int numViolations = p.readInt();
         for (int i = 0; i < numViolations; ++i) {
             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
-            ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(p);
-            crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
-
-            // Unlike the in-process violations in which case we
-            // trigger an error _before_ the thing occurs, in this
-            // case the violating thing has already occurred, so we
-            // can't use our heuristic of waiting for the next event
-            // loop idle cycle to measure the approximate violation
-            // duration.  Instead, just skip that step and use -1
-            // (unknown duration) for now.
-            // TODO: keep a thread-local on remote process of first
-            // violation time's uptimeMillis, and when writing that
-            // back out in Parcel reply, include in the header the
-            // violation time and use it here.
-            crashInfo.durationMillis = -1;
-
+            ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
+            info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
             BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
             if (policy instanceof AndroidBlockGuardPolicy) {
-                ((AndroidBlockGuardPolicy) policy).handleViolation(crashInfo, policyMask);
+                ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info);
             }
         }
     }
@@ -483,4 +513,113 @@
     private static void onBinderStrictModePolicyChange(int newPolicy) {
         setBlockGuardPolicy(newPolicy);
     }
+
+    /**
+     * Parcelable that gets sent in Binder call headers back to callers
+     * to report violations that happened during a cross-process call.
+     *
+     * @hide
+     */
+    public static class ViolationInfo {
+        /**
+         * Stack and other stuff info.
+         */
+        public final ApplicationErrorReport.CrashInfo crashInfo;
+
+        /**
+         * The strict mode policy mask at the time of violation.
+         */
+        public final int policy;
+
+        /**
+         * The wall time duration of the violation, when known.  -1 when
+         * not known.
+         */
+        public int durationMillis = -1;
+
+        /**
+         * Which violation number this was (1-based) since the last Looper loop,
+         * from the perspective of the root caller (if it crossed any processes
+         * via Binder calls).  The value is 0 if the root caller wasn't on a Looper
+         * thread.
+         */
+        public int violationNumThisLoop;
+
+        /**
+         * The time (in terms of SystemClock.uptimeMillis()) that the
+         * violation occurred.
+         */
+        public long violationUptimeMillis;
+
+        /**
+         * Create an uninitialized instance of ViolationInfo
+         */
+        public ViolationInfo() {
+            crashInfo = null;
+            policy = 0;
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from an exception.
+         */
+        public ViolationInfo(Throwable tr, int policy) {
+            crashInfo = new ApplicationErrorReport.CrashInfo(tr);
+            violationUptimeMillis = SystemClock.uptimeMillis();
+            this.policy = policy;
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from a Parcel.
+         */
+        public ViolationInfo(Parcel in) {
+            this(in, false);
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from a Parcel.
+         *
+         * @param unsetGatheringBit if true, the caller is the root caller
+         *   and the gathering penalty should be removed.
+         */
+        public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
+            crashInfo = new ApplicationErrorReport.CrashInfo(in);
+            int rawPolicy = in.readInt();
+            if (unsetGatheringBit) {
+                policy = rawPolicy & ~PENALTY_GATHER;
+            } else {
+                policy = rawPolicy;
+            }
+            durationMillis = in.readInt();
+            violationNumThisLoop = in.readInt();
+            violationUptimeMillis = in.readLong();
+        }
+
+        /**
+         * Save a ViolationInfo instance to a parcel.
+         */
+        public void writeToParcel(Parcel dest, int flags) {
+            crashInfo.writeToParcel(dest, flags);
+            dest.writeInt(policy);
+            dest.writeInt(durationMillis);
+            dest.writeInt(violationNumThisLoop);
+            dest.writeLong(violationUptimeMillis);
+        }
+
+
+        /**
+         * Dump a ViolationInfo instance to a Printer.
+         */
+        public void dump(Printer pw, String prefix) {
+            crashInfo.dump(pw, prefix);
+            pw.println(prefix + "policy: " + policy);
+            if (durationMillis != -1) {
+                pw.println(prefix + "durationMillis: " + durationMillis);
+            }
+            if (violationNumThisLoop != 0) {
+                pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
+            }
+            pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
+        }
+
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7bb89f5..ea26207 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3373,6 +3373,14 @@
         public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC =
                 "throttle_max_ntp_cache_age_sec";
 
+        /**
+         * The maximum size, in bytes, of a download that the download manager will transfer over
+         * a non-wifi connection.
+         * @hide
+         */
+        public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
+                "download_manager_max_bytes_over_mobile";
+
 
         /**
          * @hide
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 396b7ae..b4d6ad7 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -43,14 +43,14 @@
     }
     
     /**
-     * {@see DataSetObservable#notifyInvalidated()}
+     * @see DataSetObservable#notifyInvalidated()
      */
     public void notifyDataSetInvalidated() {
         mDataSetObservable.notifyInvalidated();
     }
     
     /**
-     * {@see DataSetObservable#notifyChanged()}
+     * @see DataSetObservable#notifyChanged()
      */
     public void notifyDataSetChanged() {
         mDataSetObservable.notifyChanged();
diff --git a/core/java/android/widget/HeterogeneousExpandableList.java b/core/java/android/widget/HeterogeneousExpandableList.java
index 1292733..e7e0933 100644
--- a/core/java/android/widget/HeterogeneousExpandableList.java
+++ b/core/java/android/widget/HeterogeneousExpandableList.java
@@ -23,12 +23,13 @@
  * Additional methods that when implemented make an
  * {@link ExpandableListAdapter} take advantage of the {@link Adapter} view type
  * mechanism.
- * 
- * An {@link ExpandableListAdapter} declares one view type for its group items
+ * <p>
+ * An {@link ExpandableListAdapter} declares it has one view type for its group items
  * and one view type for its child items. Although adapted for most {@link ExpandableListView}s,
- * these values should be tuned heterogeneous {@link ExpandableListView}s. Lists that contain
- * different types of group and/or child item views, should use an adapter that implements this
- * interface. This way, the recycled views that will be provided to
+ * these values should be tuned for heterogeneous {@link ExpandableListView}s.
+ * </p>
+ * Lists that contain different types of group and/or child item views, should use an adapter that
+ * implements this interface. This way, the recycled views that will be provided to
  * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
  * and
  * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
@@ -48,7 +49,7 @@
      *         . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
      *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
      * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
-     * @see getGroupTypeCount()
+     * @see #getGroupTypeCount()
      */
     int getGroupType(int groupPosition);
 
@@ -65,7 +66,7 @@
      *         Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
      *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
      * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
-     * @see getChildTypeCount()
+     * @see #getChildTypeCount()
      */
     int getChildType(int groupPosition, int childPosition);
 
@@ -78,13 +79,11 @@
      * . If the adapter always returns the same type of View for all group items, this method should
      * return 1.
      * </p>
-     * <p>
      * This method will only be called when the adapter is set on the {@link AdapterView}.
-     * </p>
      * 
      * @return The number of types of group Views that will be created by this adapter.
-     * @see getChildTypeCount()
-     * @see getGroupType()
+     * @see #getChildTypeCount()
+     * @see #getGroupType(int)
      */
     int getGroupTypeCount();
 
@@ -97,13 +96,11 @@
      * , for any group. If the adapter always returns the same type of View for
      * all child items, this method should return 1.
      * </p>
-     * <p>
      * This method will only be called when the adapter is set on the {@link AdapterView}.
-     * </p>
      * 
      * @return The total number of types of child Views that will be created by this adapter.
-     * @see getGroupTypeCount()
-     * @see getChildType()
+     * @see #getGroupTypeCount()
+     * @see #getChildType(int, int)
      */
     int getChildTypeCount();
 }
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7b23418..e29495c 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -38,6 +38,7 @@
     jfieldID    range;
     jfieldID    resolution;
     jfieldID    power;
+    jfieldID    minDelay;
 } gSensorOffsets;
 
 /*
@@ -74,6 +75,7 @@
     env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
     env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
     env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
+    env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     
     next++;
     return next<count ? next : 0;
@@ -154,6 +156,7 @@
     sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
     sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
     sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
+    sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index cdaefc8..ad8d444 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -91,30 +91,30 @@
     //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
     private void waitForNetworkState(int networkType, State expectedState, long timeout) {
         long startTime = System.currentTimeMillis();
-        // In case the broadcast is already sent out, no need to wait
-        if (cmActivity.mCM.getNetworkInfo(networkType).getState() == expectedState) {
-            return;
-        } else {
-            while (true) {
-                if ((System.currentTimeMillis() - startTime) > timeout) {
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (cmActivity.mCM.getNetworkInfo(networkType).getState() != expectedState) {
                     assertFalse("Wait for network state timeout", true);
+                } else {
+                    // the broadcast has been sent out. the state has been changed.
+                    return;
                 }
-                Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
-                        " to be " + expectedState.toString());
-                synchronized (cmActivity.connectivityObject) {
-                    try {
-                        cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                    if ((cmActivity.mNetworkInfo.getType() != networkType) ||
-                        (cmActivity.mNetworkInfo.getState() != expectedState)) {
-                        Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
-                                "is: " + cmActivity.mNetworkInfo.getState());
-                        continue;
-                    }
-                    break;
+            }
+            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+                    " to be " + expectedState.toString());
+            synchronized (cmActivity.connectivityObject) {
+                try {
+                    cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
                 }
+                if ((cmActivity.mNetworkInfo.getType() != networkType) ||
+                    (cmActivity.mNetworkInfo.getState() != expectedState)) {
+                    Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
+                            "is: " + cmActivity.mNetworkInfo.getState());
+                    continue;
+                }
+                break;
             }
         }
     }
@@ -123,26 +123,26 @@
     //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
     private void waitForWifiState(int expectedState, long timeout) {
         long startTime = System.currentTimeMillis();
-        if (cmActivity.mWifiState == expectedState) {
-            return;
-        } else {
-            while (true) {
-                if ((System.currentTimeMillis() - startTime) > timeout) {
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (cmActivity.mWifiState != expectedState) {
                     assertFalse("Wait for Wifi state timeout", true);
+                } else {
+                    return;
                 }
-                Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
-                synchronized (cmActivity.wifiObject) {
-                    try {
-                        cmActivity.wifiObject.wait(5*1000);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                    if (cmActivity.mWifiState != expectedState) {
-                        Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
-                        continue;
-                    }
-                    break;
+            }
+            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+            synchronized (cmActivity.wifiObject) {
+                try {
+                    cmActivity.wifiObject.wait(5*1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
                 }
+                if (cmActivity.mWifiState != expectedState) {
+                    Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
+                    continue;
+                }
+                break;
             }
         }
     }
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index e3b9135..07af68d 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -154,7 +154,7 @@
 <p>When the application receives a signed response, it uses the embedded public
 key to verify the data. The use of public key cryptography in the licensing
 service makes it possible for the application to detect responses that have been
-tampered with or are spoofed.</p>
+tampered with or that are spoofed.</p>
 
 <h4>Use of licensing in your application</h4>
 
@@ -184,7 +184,7 @@
 and helps ensure a more secure, robust implementation for your application. The
 LVL provides internal classes that handle most of the standard operations of a
 license query, such as contacting Android Market to initiate a license request
-and decrypting and validating the responses. It also exposes key interfaces that
+and verifying and validating the responses. It also exposes key interfaces that
 let you easily plug in your custom code for defining licensing policy and
 managing access as needed by your application. The key LVL interfaces are: </p>
 
@@ -211,7 +211,7 @@
 <li><a href="#ServerManagedPolicy">ServerManagedPolicy</a> is a flexible Policy
 that uses settings provided by the licensing server to manage response caching
 and access to the application while the device is offline (such as when the
-user is on on an airplane). For most applications, the use of
+user is on an airplane). For most applications, the use of
 ServerManagedPolicy is highly recommended. </li>
 <li><a href="#StrictPolicy">StrictPolicy</a> is a restrictive Policy that
 does not cache any response data and allows the application access <em>only</em>
@@ -233,10 +233,10 @@
 <h4>Requirements and limitations</h4>
 
 <p>Android Market Licensing is designed to let you apply license controls to
-applications that you publish through Android Market and that users download
-from Market. The service is not designed to let you control access to
-applications that are not published through Android Market or that are run
-on devices that do not offer the Android Market client. </p>
+applications that you publish through Android Market. The service is not
+designed to let you control access to applications that are not published
+through Android Market or that are run on devices that do not offer the Android
+Market client. </p>
 
 <p>Here are some points to keep in mind as you implement licensing in your
 application: </p>
@@ -267,14 +267,15 @@
 
 <p>Android Market Licensing is a flexible, secure mechanism for controlling
 access to your applications. It effectively replaces the copy-protection
-mechanism and gives you wider distribution potential for your applications. </p>
+mechanism offered on Android Market and gives you wider distribution
+potential for your applications. </p>
 
 <ul>
-<li>A limitation of copy protection is that applications using it can be
-installed only on compatible devices that provide a secure internal storage
-environment. For example, a copy-protected application cannot be downloaded
-from Market to a device that provides root access, and the application
-cannot be installed to a device's SD card. </li>
+<li>A limitation of the legacy copy-protection mechanism on Android Market is
+that applications using it can be installed only on compatible devices that
+provide a secure internal storage environment. For example, a copy-protected
+application cannot be downloaded from Market to a device that provides root
+access, and the application cannot be installed to a device's SD card. </li>
 <li>With Android Market licensing, you can move to a license-based model in
 which access is not bound to the characteristics of the host device, but to your
 publisher account on Android Market and the licensing policy that you define.
@@ -338,7 +339,7 @@
 <ul>
 <li>Set up multiple "test accounts", identified by email address. The licensing
 server allows users signed into test accounts on a device or emulator to send
-license checks and receive static test reponses.</li>
+license checks and receive static test responses.</li>
 <li>Obtain the account's public key for licensing. When you are implementing
 licensing in an application, you must copy the public key string into the
 application.</li>
@@ -402,7 +403,7 @@
 <p>If you haven't done so, you need to download the Android SDK before you can
 develop Android applications. The SDK provides the tools that you need to build
 and debug Android applications, including applications that use Android Market
-licensing. For complete information, including installation intructions, see
+licensing. For complete information, including installation instructions, see
 the <a href="{@docRoot}sdk/index.html">Android SDK</a>. </p>
 
 <p>If you have already installed the SDK, make sure to update the
@@ -472,7 +473,7 @@
 
 <ul>
 <li>An Android Market background service that implements the
-<code>ILicensingService</code> remote interface, so that your application can
+ILicensingService remote interface, so that your application can
 send license checks over the network to the licensing server. </li>
 <li>A set of underlying account services that let you add an a Google account on
 the AVD and sign in using your publisher account or test account credentials.
@@ -492,7 +493,7 @@
 <img src="{@docRoot}images/licensing_gapis_8.png" style="text-align:left;margin-bottom:0;" />
 <div style="margin:0 2em;padding:0"><strong>Figure 3.</strong> Google APIs
 Add-On, API 8 (release 2) or higher lets you debug and test your licensing
-implemention in an emulator.</div>
+implementation in an emulator.</div>
 </div>
 
 <p>To set up an emulator for adding licensing to an application, follow
@@ -581,9 +582,9 @@
 <p>When the download is complete, the Android SDK and AVD Manager installs both
 the LVL library project and the example application into these directories: </p>
 
-<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/marketlicensing/library/</code>
+<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/market_licensing/library/</code>
 &nbsp;&nbsp;(the LVL library project)<br />
-<code>&lt;<em>sdk</em>&gt;/marketlicensing/sample/</code>&nbsp;&nbsp;(the example
+<code>&lt;<em>sdk</em>&gt;/market_licensing/sample/</code>&nbsp;&nbsp;(the example
 application)</p>
 
 <p>If you aren't familiar with how to download components into your SDK, see the
@@ -601,20 +602,21 @@
 maintain it more easily over time. Note that the LVL is not designed to be
 compiled separately and added to an application as a static .jar file. </p>
 
-<h4>Moving the library sources out  location</h4>
+<h4>Moving the library sources to a new location</h4>
 
 <p>Because you will be customizing the LVL sources to some extent, you should
 make sure to <em>move or copy</em> the library sources (the entire
-directory at <code>&lt;<em>sdk</em>&gt;/marketlicensing/library/</code>)
-to a working directory outside of the SDK. You can then add the sources
-in the working location to your source-code management system, rather
-than those in the SDK.</p>
+directory at <code>&lt;<em>sdk</em>&gt;/market_licensing/library/</code>)
+to a working directory outside of the SDK. You should then use the relocated
+sources as your working set. If you are using a source-code management
+system, add and track the sources that are in the working location rather
+than those in default location in the SDK. </p>
 
 <p>Moving the library sources is important is because, when you later update the
 Market licensing package, the SDK installs the new files to the same location as
 the older files. Moving your working library files to a safe location ensures
-that they won't be inadvertently overwritten when you download a new version of
-the LVL.</p>
+that your work won't be inadvertently overwritten should you download a new
+version of the LVL.</p>
 
 <h4>Creating the LVL as a library project</h4>
 
@@ -639,11 +641,11 @@
 <em>library project</em>. A library project is a type of development project
 that holds shared Android source code and resources. Other Android application
 projects can reference the library project and, at build time, include its
-compiled sources in their <code>.apk</code> files. In the context of licensing, this means
-that you can do most of your licensing development once, in a library project,
-then include the library sources in your various application projects. In this
-way, you can easily maintain a uniform implementation of licensing across all of
-your projects and maintain it centrally. </p>
+compiled sources in their <code>.apk</code> files. In the context of licensing,
+this means that you can do most of your licensing development once, in a library
+project, then include the library sources in your various application projects.
+In this way, you can easily maintain a uniform implementation of licensing
+across all of your projects and maintain it centrally. </p>
 
 <p>The LVL is provided as a configured library project &mdash; once you have
 downloaded it, you can start using it right away. </p>
@@ -675,9 +677,8 @@
 
 <p>As an alternative to adding the LVL as a library project, you can copy the
 library sources directly into your application. To do so, copy (or import) the
-directory
-<code>&lt;<em>sdk</em>&gt;/extras/marketlicensing/library/src/com</code> into
-your application's <code>src/</code> directory.</p>
+LVL's <code>library/src/com</code> directory into your application's
+<code>src/</code> directory.</p>
 
 <p>If you add the LVL sources directly to your application, you can skip the
 next section and start working with the library, as described in <a
@@ -688,10 +689,10 @@
 application</h3>
 
 <p>If you want to use the LVL sources as a library project, you need to add a
-reference to the LVL library project in your project properties. This tells
+reference to the LVL library project in your application project properties. This tells
 build tools to include the LVL library project sources in your application at
-compile time. The process for adding a reference to a library project varies,
-based on your development environment, as described below.</p>
+compile time. The process for adding a reference to a library project depends
+on your development environment, as described below.</p>
 
 <p> If you are developing in Eclipse with ADT, you should already have added the
 library project to your workspace, as described in the previous section. If you
@@ -793,10 +794,10 @@
 </pre>
 
 <p class="note"><strong>Note:</strong> Currently, you cannot declare the
-<code>CHECK_LICENSE</code> permission in the LVL's manifest, because the SDK
-Tools will not merge it into the manifests of dependent applications. Instead,
-you must declare the permission in the manifest of each dependent application.
-</p>
+<code>CHECK_LICENSE</code> permission in the LVL library project's manifest,
+because the SDK Tools will not merge it into the manifests of dependent
+applications. Instead, you must declare the permission in each dependent
+application's manifest. </p>
 
 
 <h3 id="impl-Policy">Implementing a Policy</h3>
@@ -856,7 +857,7 @@
 example, your implementation of <code>allowAccess()</code> could take into
 account additional criteria, such as usage or other data retrieved from a
 backend server. In all cases, an implementation of <code>allowAccess()</code>
-should only return <code>true</code> if there user is licensed to use the
+should only return <code>true</code> if the user is licensed to use the
 application, as determined by the licensing server, or if there is a transient
 network or system problem that prevents the license check from completing. In
 such cases, your implementation can maintain a count of retry responses and
@@ -866,7 +867,8 @@
 
 <p>To simplify the process of adding licensing to your application and to
 provide an illustration of how a Policy should be designed, the LVL includes
-two full Policy implementations that you can use without modification:</p>
+two full Policy implementations that you can use without modification or
+adapt to your needs:</p>
 
 <ul>
 <li><a href="#ServerManagedPolicy">ServerManagedPolicy</a>, a flexible Policy
@@ -886,7 +888,7 @@
 
 <p>In your licensing implementation, you can use one of the complete policies
 provided in the LVL (ServerManagedPolicy or StrictPolicy) or you can create a
-custom Policy. For any type of custom policy, there are several important design
+custom policy. For any type of custom policy, there are several important design
 points to understand and account for in your implementation.</p>
 
 <p>The licensing server applies general request limits to guard against overuse
@@ -896,7 +898,7 @@
 license response will be available to the user until the limit is reset, which
 can affect the user for an indefinite period.</p>
 
-<p>If you are designing a custom Policy, we recommend that the Policy:
+<p>If you are designing a custom policy, we recommend that the Policy:
 <ol>
 <!-- <li>Limits the number of points at which your app calls for a license check
 to the minimum. </li> -->
@@ -904,12 +906,12 @@
 in local persistent storage.</li>
 <li>Returns the cached response for all license checks, for as long as the
 cached response is valid, rather than making a request to the licensing server.
-Setting the response validity accrording to the server-provided <code>VT</code>
+Setting the response validity according to the server-provided <code>VT</code>
 extra is highly recommended. See <a href="#extras">Server Response Extras</a>
 for more information.</li>
-<li>Uses an exponential backoff period if retrying any requests the result in
-errors. However, because the Android Market client automatically retries failed
-requests, the Policy does not need to do so, in most cases.</li>
+<li>Uses an exponential backoff period, if retrying any requests the result in
+errors. Note that the Android Market client automatically retries failed
+requests, so in most cases there is no need for your Policy to retry them.</li>
 <li>Provides for a "grace period" that allows the user to access your
 application for a limited time or number of uses, while a license check is being
 retried. The grace period benefits the user by allowing access until the next
@@ -942,7 +944,7 @@
 
 <p style="margin-top:.5em;">See <a href="#extras">Server Response Extras</a> for
 a list of settings and <code>ServerManagedPolicy.java</code> for information
-about how a Policy can usethe extras.</p>
+about how a Policy can use the extras.</p>
 
 </div>
 </div>
@@ -965,8 +967,8 @@
 server-provided settings as the basis for managing licensing across an
 application's refund period and through varying network and error conditions.
 When an application contacts the Android Market server for a license check, the
-server appends several settings as key-value pairs in the license response
-extras field. For example, the server provides recommended values for the
+server appends several settings as key-value pairs in the extras field of certain
+license response types. For example, the server provides recommended values for the
 application's license validity period, retry grace period, and maximum allowable
 retry count, among others. ServerManagedPolicy extracts the values from the
 license response in its <code>processServerResponse()</code> method and checks
@@ -1019,8 +1021,7 @@
 means that they won't be able to access the application when there is no network
 (cell or wi-fi) connection available. Another side-effect is that your
 application will send more license check requests to the server, since using a
-cached response is not possible. Depending on network conditions, this might
-prove challenging for users also.</p>
+cached response is not possible.</p>
 
 <p>Overall, this policy represents a tradeoff of some degree of user convenience
 for absolute security and control over access. Consider the tradeoff carefully
@@ -1058,7 +1059,7 @@
 
 <p>Because the Policy will use stored license response data to determine whether
 to allow or disallow access to the application, it <em>must</em> ensure that any
-stored data is secure and can not be reused or manipulated by a root user on a
+stored data is secure and cannot be reused or manipulated by a root user on a
 device. Specifically, the Policy must always obfuscate the data before storing
 it, using a key that is unique for the application and device. Obfuscating using
 a key that is both application-specific and device-specific is critical, because
@@ -1066,20 +1067,18 @@
 devices.</p>
 
 <p>The LVL assists the application with storing its license response data in a
-secure, persistent manner. First, it provides an <code>Obfuscator</code>
+secure, persistent manner. First, it provides an Obfuscator
 interface that lets your application supply the obfuscation algorithm of its
 choice for stored data. Building on that, the LVL provides the helper class
-<code>PreferenceObfuscator</code>, which handles most of the work of calling the
+PreferenceObfuscator, which handles most of the work of calling the
 application's Obfuscator class and reading and writing the obfuscated data in a
 SharedPreferences instance. </p>
 
 <p>The LVL provides a full Obfuscator implementation called
-<code>AESObfuscator</code> that uses AES encryption to obfuscate data. You can
-use <code>AESObfuscator</code> in your application without modification or you
+AESObfuscator that uses AES encryption to obfuscate data. You can
+use AESObfuscator in your application without modification or you
 can adapt it to your needs. For more information, see the next section.</p>
 
-<p>Alternatively, you can write a custom Obfuscator based on your own code
-or use an obfuscator program such as ProGuard for additional security.</p>
 
 <h4 id="AESObfuscator">AESObfuscator</h4>
 
@@ -1118,14 +1117,16 @@
 <code>android.Settings.Secure.ANDROID_ID</code>, which is unique to each device.
 </p>
 
-<p>Note that, depending on the APIs you use to derive device-specific
-information, your application might need to request additional permissions in
-order to secure device-specific information. For example, if you query the
-TelephonyManager to obtain the device IMEI or related data, your application
-will also need to request the <code>android.permission.READ_PHONE_STATE</code>
-permission in its manifest. Before requesting permissions in this way, consider
-how doing so might affect your application or its filtering of your application
-on Android Market (since some permissions can cause the SDK build tools to add
+<p>Note that, depending on the APIs you use, your application might need to
+request additional permissions in order to acquire device-specific information.
+For example, to query the {@link android.telephony.TelephonyManager} to obtain
+the device IMEI or related data, the application will also need to request the
+<code>android.permission.READ_PHONE_STATE</code> permission in its manifest.</p>
+
+<p>Before requesting new permissions for the <em>sole purpose</em> of acquiring
+device-specific information for use in your Obfuscator, consider
+how doing so might affect your application or its filtering on Android Market
+(since some permissions can cause the SDK build tools to add
 the associated <code>&lt;uses-feature&gt;</code>).</p>
 
 <p>Finally, construct an instance of AESObfuscator, passing the salt,
@@ -1441,7 +1442,7 @@
 </ul>
 
 <p>If you are using ServerManagedPolicy, you won't need to access the class
-directly, so you can instantiate it directly in the LicenseChecker constructor,
+directly, so you can instantiate it in the LicenseChecker constructor,
 as shown in the example below. Note that you need to pass a reference to a new
 Obfuscator instance when you construct ServerManagedPolicy.</p>
 
@@ -1510,7 +1511,7 @@
 <h4 id="account-key">Embed your public key for licensing</h4>
 
 <p>For each publisher account, the Android Market service automatically
-generates a  2048-bit RSA public/private key pair that is used exlusively for
+generates a  2048-bit RSA public/private key pair that is used exclusively for
 licensing. The key pair is uniquely associated with the publisher account and is
 shared across all applications that are published through the account. Although
 associated with a publisher account, the key pair is <em>not</em> the same as
@@ -1562,14 +1563,14 @@
 application's ILicensingService and removes any local references to the service
 and handler.</p>
 
-<p>Failing to add the call the LicenseChecker's <code>onDestroy()</code> method
+<p>Failing to call the LicenseChecker's <code>onDestroy()</code> method
 can lead to problems over the lifecycle of your application. For example, if the
 user changes screen orientation while a license check is active, the application
 {@link android.content.Context} is destroyed. If your application does not
 properly close the LicenseChecker's IPC connection, your application will crash
 when the response is received. Similarly, if the user exits your application
 while a license check is in progress,  your application will crash when the
-response is received, unless your application has properly called the
+response is received, unless it has properly called the
 LicenseChecker's <code>onDestroy()</code> method to disconnect from the service.
 </p>
 
@@ -1608,7 +1609,7 @@
 required</strong> &mdash; the LicenseChecker class automatically uses a default
 implementation called NullDeviceLimiter. As the name suggests, NullDeviceLimiter
 is a "no-op" class whose <code>allowDeviceAccess()</code> method simply returns
-a LICENSED response for all users and devices. </p>
+a <code>LICENSED</code> response for all users and devices. </p>
 
 <div style="border-left:4px solid #FFCF00;margin:1em;padding: 0 0 0 .5em">
 <p><strong>Caution:</strong> Per-device licensing is <em>not recommended for
@@ -1634,15 +1635,15 @@
 
 <ul>
 <li>A "Test response" configuration in your publisher account that lets you
-control the licensing response returned, when the server processes a license
-check for an uploaded application from the publisher account or a test
-account.</li>
-<li>An optional set of test accounts that will receive the configured test
-response when checking the license of an application that you have uploaded
+set the static licensing response returned, when the server processes a
+license check for an application uploaded to the publisher account, from a user
+signed in to the publisher account or a test account.</li>
+<li>An optional set of test accounts that will receive the static test
+response when they check the license of an application that you have uploaded
 (regardless whether the application is published or not).</li>
 <li>A runtime environment for the application that includes the Android Market
 application or Google APIs Add-On, on which the user is signed in to the
-publisher account or one of the test accounts.
+publisher account or one of the test accounts.</li>
 </ul>
 
 <p>Setting up the test environment properly involves:</p>
@@ -1659,11 +1660,12 @@
 <h3 id="test-response">Setting test responses for license checks</h3>
 
 <p>Android Market provides a configuration setting in your publisher account
-that lets you override the normal processing of a license check for an
-application you have uploaded and return a specified response code. The setting
-is for testing only and applies <em>only</em> to license checks for applications
-that you have uploaded. For other users (users not signed in to test accounts),
-the server always processes license checks according to normal rules.  </p>
+that lets you override the normal processing of a license check and return a
+specified static response code. The setting is for testing only and applies
+<em>only</em> to license checks for applications that you have uploaded, made by
+any user signed in to an emulator or device using the credentials of the
+publisher account or a registered test account. For other users, the server
+always processes license checks according to normal rules.  </p>
 
 <p>To set a test response for your account, sign in to your publisher account
 and click "Edit Profile". In the Edit Profile page, locate the Test Response
@@ -1672,9 +1674,9 @@
 test in your application.</p>
 
 <p>In general, you should make sure to test your application's licensing
-implementation with every response code available in the Test Response" menu.
+implementation with every response code available in the Test Response menu.
 For a description of the codes, see <a href="#server-response-codes">Server
-Response Codes</a>, below.</p>
+Response Codes</a> in the Appendix of this document.</p>
 
 <div style="margin-bottom:2em;" id="licensing_test_response">
 
@@ -1688,10 +1690,11 @@
 that is, it applies not to a single application, but to <em>all</em>
 applications associated with the publisher account. If you are testing multiple
 applications at once, changing the test response will affect all of those
-applications on their next license check.</p>
+applications on their next license check (if the user is signed into
+the emulator or device using the publisher account or a test account).</p>
 
-<p>Finally, before you can successfully send these test responses to your
-application, you must sign in to the device or emulator on which the application
+<p>Before you can successfully receive a test response for a license check,
+you must sign in to the device or emulator on which the application
 is installed, and from which it is querying the server. Specifically, you must
 sign using either your publisher account or one of the test accounts that you
 have set up. For more information about test accounts, see the next section.</p>
@@ -1799,7 +1802,7 @@
 <p>The licensing server handles static test responses in the normal way,
 including signing the license response data, adding extras parameters, and so
 on. To support developers who are implementing licensing using test accounts,
-rather than having access to the publisher account, you will need to distribute
+rather than the publisher account, you will need to distribute
 your public key to them. Developers without access to the publisher site do not
 have access to your public key, and without the key they won't be able to
 verify license responses. </p>
@@ -2176,7 +2179,7 @@
 <td>No </td>
 <td></td>
 <td><em>Do not retry the license check.</em>
-<p style="margin-top:.5em;">Typically caused by a developement error.</p>
+<p style="margin-top:.5em;">Typically caused by a development error.</p>
 </td>
 </tr>
 <tr>
@@ -2187,7 +2190,7 @@
 <td>No </td>
 <td></td>
 <td><em>Do not retry the license check.</em>
-<p style="margin-top:.5em;">Typically caused by a developement error.</p>
+<p style="margin-top:.5em;">Typically caused by a development error.</p>
 </td>
 </tr>
 <tr>
@@ -2295,7 +2298,7 @@
 
 <ul>
 <li>For a paid application, the server sets the initial license validity period
-so that the license reponse remains valid for as long as the application is
+so that the license response remains valid for as long as the application is
 refundable. A licensing Policy in the application may cache the
 result of the initial license check and does not need to recheck the license
 until the validity period has expired.</li>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 7e2f8a0..1d6ab25 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -450,8 +450,8 @@
 to match the device density.</li>
         </ul>
         <p><em>Added in API Level 4.</em></p>
-        <p>There is thus a 4:3 scaling factor between each density, so a 9x9 bitmap
-         in ldpi is 12x12 in mdpi and 16x16 in hdpi.</p>
+        <p>There is thus a 3:4:6 scaling ratio between the three densities, so a 9x9 bitmap
+         in ldpi is 12x12 in mdpi and 18x18 in hdpi.</p>
         <p>When Android selects which resource files to use,
          it handles screen density differently than the other qualifiers.
          In step 1 of <a href="#BestMatch">How Android finds the best
@@ -895,7 +895,7 @@
 drawable-port-notouch-12key/
 </pre>
 <p class="note"><strong>Exception:</strong> Screen pixel density is the one qualifier that is not
-eliminated due to a contradiction. Even though the screen density of the device is mdpi,
+eliminated due to a contradiction. Even though the screen density of the device is hdpi,
 <code>drawable-port-ldpi/</code> is not eliminated because every screen density is
 considered to be a match at this point. More information is available in the <a
 href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
@@ -922,9 +922,8 @@
 <strike>drawable-port-notouch-12key/</strike>
 </pre>
 <p class="note"><strong>Exception:</strong> If the qualifier in question is screen pixel density,
-Android
-selects the option that most closely matches the device, and the selection process is complete.
-In general, Android prefers scaling down a larger original image to scaling  up a smaller
+Android selects the option that most closely matches the device screen density.
+In general, Android prefers scaling down a larger original image to scaling up a smaller
 original image. See <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
 Screens</a>.</p>
   </li>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 01940e8..f37a122 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -163,12 +163,11 @@
       'img':"devphone-large.png",
       'title':"Android Dev Phones",
       'desc': "<p>Run and debug your Android applications directly on one of these "
- + "device. Modify and rebuild the Android operating system, and flash it onto "
- + "the phone. The Android Dev Phones are carrier independent, and available for "
- + "purchase by any developer registered with <a "
- + "href='http://market.android.com/publish'>Android Market</a>.</p><p><a "
- + "href='/guide/developing/device.html#dev-phone-1'>Learn more about the "
- + "Android Dev Phones &raquo;</a></p>"
+ + "devices. Modify and rebuild the Android operating system, and flash it onto "
+ + "the phone. The Android Dev Phones are carrier-independent, and available for "
+ + "purchase by developers through their Android Market publisher accounts.</p><p> "
+ + "<a href='http://market.android.com/publish'>Visit Android Market "
+ + "to learn more &raquo;</a></p>"
     },
 
     'mapskey': {
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index d4b6db5..ec47796 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,8 +52,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.3,18.9,22.1,55.5,3.3&chl=Other*|
-Android%201.5|Android%201.6|Android%202.1|Android%202.2&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:15.3,20.3,0.2,59.7,4.5&chl=
+Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
+6fad0c" />
 
 <table>
 <tr>
@@ -61,14 +62,14 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>18.9%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>22.1%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>55.5%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>3.3%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>15.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>20.3%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>59.7%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>4.5%</td></tr>
 </table>
 
-<p><em>Data collected during two weeks ending on July 15, 2010</em></p>
-<p style="font-size:.9em">* <em>Other: 0.3% of devices running obsolete versions</em></p>
+<p><em>Data collected during two weeks ending on August 2, 2010</em></p>
+<p style="font-size:.9em">* <em>Other: 0.2% of devices running obsolete versions</em></p>
 
 </div><!-- end dashboard-panel -->
 
@@ -94,21 +95,20 @@
 
 <div class="dashboard-panel">
 
-<img alt="" height="265" width="700" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=700x265&chxt=x,y,r&chxr=0,0,10%7C1,0,100%7C2,0,
-100&chxl=0%3A%7C2010/02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%
-7C2010/07/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%
-7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10&chxtc=0,5&chd=t:99.0,99.2,99.4,99.5,99.6,99.6,99.6,99.7,100.6
-,101.1,99.9%7C63.4,62.5,61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6%7C22.6,23.2,24.3,25.4,29.4,30.2
-,32.7,35.3,46.2,51.3,55.1%7C0.0,0.0,0.0,0.0,4.0,28.3,32.0,34.9,45.9,51.0,54.9%7C0.0,0.0,0.0,0.0,0.0,
-0.0,0.0,0.0,0.8,1.2,1.8&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5%7Cb,c3df9b,0,1,0%7CtAndroid%201.6,
-638d23,1,0,15,,t::-5%7Cb,b0db6e,1,2,0%7CtAndroid%202.0.1,496c13,2,0,15,,t::-5%7Cb,9ddb3d,2,3,0%
-7CtAndroid%202.1,2f4708,3,5,15,,t::-5%7Cb,89cf19,3,4,0%7CB,6fad0c,4,5,0&chg=9,25&chdl=Android%201.5%
-20(API%20Level%203)%7CAndroid%201.6%20(API%20Level%204)%7CAndroid%202.0.1%20(API%20Level%206)%
-7CAndroid%202.1%20(API%20Level%207)%7CAndroid%202.2%20(API%20Level %208)&chco=add274,
-9ad145,84c323,6ba213,507d08" />
+<img alt="" height="250" width="660" style="padding:5px;background:#fff"
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
+chxl=0%3A%7C2010/02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/
+01%7C07/15%7C2010/08/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
+%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.0,99.2,99.4,99.5,99.6,99.6,
+99.6,99.7,100.6,101.1,99.9,100.0,100.0|63.4,62.5,61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6,81.1,
+84.5|22.6,23.2,24.3,25.4,29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1|0.0,0.0,0.0,0.0,4.0,28.3,32.0,
+34.9,45.9,51.0,54.9,58.8,64.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.8,1.2,1.8,3.3,4.3&chm=tAndroid%201.5
+,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid%202
+.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid%202.1,2f4708,3,5,15,,t::-5|b,89cf19,3,4,0|B,6fad0c
+,4,5,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.0.1|Android%202.1|Android%202.2&chco=
+add274,9ad145,84c323,6ba213,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on July 1, 2010</em></p>
+<p><em>Last historical dataset collected during two weeks ending on August 2, 2010</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index b20b17d..90f3f1a 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -49,8 +49,8 @@
 <div class="dashboard-panel">
 
 <img alt="" width="460" height="250"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:1.8,51.5,46.6&chl=Small%20/%20ldpi|
-Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.3,0.4,45.9,51.2&chl=Small%20/%
+20ldpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20hdpi&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -60,22 +60,22 @@
 <th scope="col">High Density</th>
 </tr>
 <tr><th scope="row">Small</th> 
-<td class='cent hi'>1.8%</td> 
+<td class='cent hi'>2.3%</td> 
 <td></td> 
 <td></td> 
 </tr> 
 <tr><th scope="row">Normal</th> 
-<td></td> 
-<td class='cent hi'>51.5%</td> 
-<td class='cent hi'>46.6%</td> 
+<td class='cent '>0.4%</td> 
+<td class='cent hi'>45.9%</td> 
+<td class='cent hi'>51.2%</td> 
 </tr> 
 <tr><th scope="row">Large</th> 
 <td></td> 
 <td></td> 
 <td></td> 
-</tr>
+</tr> 
 </table>
 
-<p><em>Data collected during two weeks ending on July 15, 2010</em></p>
+<p><em>Data collected during two weeks ending on August 2, 2010</em></p>
 </div>
 
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 9974f2f..964700b 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (C) 2008 HTC Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index e696d63..2de07b1 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -63,6 +63,7 @@
     float getMaxValue() const;
     float getResolution() const;
     float getPowerUsage() const;
+    int32_t getMinDelay() const;
 
     // Flattenable interface
     virtual size_t getFlattenedSize() const;
@@ -81,6 +82,7 @@
     float   mMaxValue;
     float   mResolution;
     float   mPower;
+    int32_t mMinDelay;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index ad36dac..6581ae3 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -65,7 +65,7 @@
     status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;
 
     // these are here only to support SensorManager.java
-    status_t enableSensor(int32_t handle, int32_t ms) const;
+    status_t enableSensor(int32_t handle, int32_t us) const;
     status_t disableSensor(int32_t handle) const;
 
 private:
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index cfc17a5..54adca8 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, 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.
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index f75d80d..c091c39 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, 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.
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index d7ec8ea..6bf1bfa 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -210,7 +210,7 @@
  * IMPORTANT INVARIANT:
  *     Because the policy and dispatcher can potentially block or cause re-entrance into
  *     the input reader, the input reader never calls into other components while holding
- *     an exclusive internal lock.
+ *     an exclusive internal lock whenever re-entrance can happen.
  */
 class InputReader : public InputReaderInterface, private InputReaderContext {
 public:
@@ -414,6 +414,8 @@
     virtual int32_t getMetaState();
 
 private:
+    Mutex mLock;
+
     struct KeyDown {
         int32_t keyCode;
         int32_t scanCode;
@@ -423,17 +425,22 @@
     uint32_t mSources;
     int32_t mKeyboardType;
 
-    Vector<KeyDown> mKeyDowns; // keys that are down
-    int32_t mMetaState;
-    nsecs_t mDownTime; // time of most recent key down
+    struct LockedState {
+        Vector<KeyDown> keyDowns; // keys that are down
+        int32_t metaState;
+        nsecs_t downTime; // time of most recent key down
+    } mLocked;
 
-    void initialize();
+    void initializeLocked();
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
+
     void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
             uint32_t policyFlags);
+    void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags,
+            bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
 
-    ssize_t findKeyDown(int32_t scanCode);
+    ssize_t findKeyDownLocked(int32_t scanCode);
 };
 
 
@@ -451,6 +458,8 @@
     // Amount that trackball needs to move in order to generate a key event.
     static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
 
+    Mutex mLock;
+
     int32_t mAssociatedDisplayId;
 
     struct Accumulator {
@@ -475,17 +484,21 @@
         }
     } mAccumulator;
 
-    bool mDown;
-    nsecs_t mDownTime;
-
     float mXScale;
     float mYScale;
     float mXPrecision;
     float mYPrecision;
 
-    void initialize();
+    struct LockedState {
+        bool down;
+        nsecs_t downTime;
+    } mLocked;
+
+    void initializeLocked();
 
     void sync(nsecs_t when);
+    void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
+            PointerCoords* pointerCoords, nsecs_t downTime);
 };
 
 
@@ -509,6 +522,8 @@
      * (This is limited by our use of BitSet32 to track pointer assignments.) */
     static const uint32_t MAX_POINTER_ID = 31;
 
+    Mutex mLock;
+
     struct VirtualKey {
         int32_t keyCode;
         int32_t scanCode;
@@ -561,7 +576,6 @@
     };
 
     int32_t mAssociatedDisplayId;
-    Vector<VirtualKey> mVirtualKeys;
 
     // Immutable configuration parameters.
     struct Parameters {
@@ -583,67 +597,65 @@
         RawAbsoluteAxisInfo orientation;
     } mAxes;
 
-    // The surface orientation and width and height set by configureSurface().
-    int32_t mSurfaceOrientation;
-    int32_t mSurfaceWidth, mSurfaceHeight;
-
-    // Translation and scaling factors, orientation-independent.
-    int32_t mXOrigin;
-    float mXScale;
-    float mXPrecision;
-
-    int32_t mYOrigin;
-    float mYScale;
-    float mYPrecision;
-
-    int32_t mPressureOrigin;
-    float mPressureScale;
-
-    int32_t mSizeOrigin;
-    float mSizeScale;
-
-    float mOrientationScale;
-
-    // Oriented motion ranges for input device info.
-    struct OrientedRanges {
-        InputDeviceInfo::MotionRange x;
-        InputDeviceInfo::MotionRange y;
-        InputDeviceInfo::MotionRange pressure;
-        InputDeviceInfo::MotionRange size;
-        InputDeviceInfo::MotionRange touchMajor;
-        InputDeviceInfo::MotionRange touchMinor;
-        InputDeviceInfo::MotionRange toolMajor;
-        InputDeviceInfo::MotionRange toolMinor;
-        InputDeviceInfo::MotionRange orientation;
-    } mOrientedRanges;
-
-    // Oriented dimensions and precision.
-    float mOrientedSurfaceWidth, mOrientedSurfaceHeight;
-    float mOrientedXPrecision, mOrientedYPrecision;
-
-    // The touch data of the current sample being processed.
+    // Current and previous touch sample data.
     TouchData mCurrentTouch;
-
-    // The touch data of the previous sample that was processed.  This is updated
-    // incrementally while the current sample is being processed.
     TouchData mLastTouch;
 
     // The time the primary pointer last went down.
     nsecs_t mDownTime;
 
-    struct CurrentVirtualKeyState {
-        bool down;
-        nsecs_t downTime;
-        int32_t keyCode;
-        int32_t scanCode;
-    } mCurrentVirtualKey;
+    struct LockedState {
+        Vector<VirtualKey> virtualKeys;
 
-    // Lock for virtual key state.
-    Mutex mVirtualKeyLock; // methods use "Lvk" suffix
+        // The surface orientation and width and height set by configureSurfaceLocked().
+        int32_t surfaceOrientation;
+        int32_t surfaceWidth, surfaceHeight;
+
+        // Translation and scaling factors, orientation-independent.
+        int32_t xOrigin;
+        float xScale;
+        float xPrecision;
+
+        int32_t yOrigin;
+        float yScale;
+        float yPrecision;
+
+        int32_t pressureOrigin;
+        float pressureScale;
+
+        int32_t sizeOrigin;
+        float sizeScale;
+
+        float orientationScale;
+
+        // Oriented motion ranges for input device info.
+        struct OrientedRanges {
+            InputDeviceInfo::MotionRange x;
+            InputDeviceInfo::MotionRange y;
+            InputDeviceInfo::MotionRange pressure;
+            InputDeviceInfo::MotionRange size;
+            InputDeviceInfo::MotionRange touchMajor;
+            InputDeviceInfo::MotionRange touchMinor;
+            InputDeviceInfo::MotionRange toolMajor;
+            InputDeviceInfo::MotionRange toolMinor;
+            InputDeviceInfo::MotionRange orientation;
+        } orientedRanges;
+
+        // Oriented dimensions and precision.
+        float orientedSurfaceWidth, orientedSurfaceHeight;
+        float orientedXPrecision, orientedYPrecision;
+
+        struct CurrentVirtualKeyState {
+            bool down;
+            nsecs_t downTime;
+            int32_t keyCode;
+            int32_t scanCode;
+        } currentVirtualKey;
+    } mLocked;
 
     virtual void configureAxes();
-    virtual bool configureSurface();
-    virtual void configureVirtualKeys();
+    virtual bool configureSurfaceLocked();
+    virtual void configureVirtualKeysLocked();
 
     enum TouchResult {
         // Dispatch the touch normally.
@@ -696,15 +708,19 @@
         uint64_t distance : 48; // squared distance
     };
 
-    void initialize();
+    void initializeLocked();
 
     TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
             BitSet32 idBits, uint32_t changedId, int32_t motionEventAction);
 
-    bool isPointInsideSurface(int32_t x, int32_t y);
-    const VirtualKey* findVirtualKeyHitLvk(int32_t x, int32_t y);
+    void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
+            int32_t keyEventAction, int32_t keyEventFlags,
+            int32_t keyCode, int32_t scanCode, nsecs_t downTime);
+
+    bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
+    const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
 
     bool applyBadTouchFilter();
     bool applyJumpyTouchFilter();
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 0037399..7efc6d7 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index cb85df9..b1f37ff 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -32,7 +32,7 @@
 Sensor::Sensor()
     : mHandle(0), mType(0),
       mMinValue(0), mMaxValue(0), mResolution(0),
-      mPower(0)
+      mPower(0), mMinDelay(0)
 {
 }
 
@@ -46,6 +46,7 @@
     mMaxValue = hwSensor->maxRange;     // FIXME: maxValue
     mResolution = hwSensor->resolution;
     mPower = hwSensor->power;
+    mMinDelay = hwSensor->minDelay;
 }
 
 Sensor::~Sensor()
@@ -84,12 +85,17 @@
     return mPower;
 }
 
+int32_t Sensor::getMinDelay() const {
+    return mMinDelay;
+}
+
 size_t Sensor::getFlattenedSize() const
 {
     return  sizeof(int32_t) + ((mName.length() + 3) & ~3) +
             sizeof(int32_t) + ((mVendor.length() + 3) & ~3) +
             sizeof(int32_t) * 2 +
-            sizeof(float) * 4;
+            sizeof(float) * 4 +
+            sizeof(int32_t);
 }
 
 size_t Sensor::getFdCount() const
@@ -132,6 +138,7 @@
     offset += write(buffer, offset, mMaxValue);
     offset += write(buffer, offset, mResolution);
     offset += write(buffer, offset, mPower);
+    offset += write(buffer, offset, mMinDelay);
 
     return NO_ERROR;
 }
@@ -169,6 +176,7 @@
     offset += read(buffer, offset, &mMaxValue);
     offset += read(buffer, offset, &mResolution);
     offset += read(buffer, offset, &mPower);
+    offset += read(buffer, offset, &mMinDelay);
 
     return NO_ERROR;
 }
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 4b46842..3396f25 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -114,10 +114,10 @@
     return mSensorEventConnection->enableDisable(sensor->getHandle(), false);
 }
 
-status_t SensorEventQueue::enableSensor(int32_t handle, int32_t ms) const {
+status_t SensorEventQueue::enableSensor(int32_t handle, int32_t us) const {
     status_t err = mSensorEventConnection->enableDisable(handle, true);
     if (err == NO_ERROR) {
-        mSensorEventConnection->setEventRate(handle, ms2ns(ms));
+        mSensorEventConnection->setEventRate(handle, us2ns(us));
     }
     return err;
 }
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 56e2977..6618702 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -713,15 +713,15 @@
         uint32_t sources, int32_t keyboardType) :
         InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
         mKeyboardType(keyboardType) {
-    initialize();
+    initializeLocked();
 }
 
 KeyboardInputMapper::~KeyboardInputMapper() {
 }
 
-void KeyboardInputMapper::initialize() {
-    mMetaState = AMETA_NONE;
-    mDownTime = 0;
+void KeyboardInputMapper::initializeLocked() {
+    mLocked.metaState = AMETA_NONE;
+    mLocked.downTime = 0;
 }
 
 uint32_t KeyboardInputMapper::getSources() {
@@ -735,17 +735,27 @@
 }
 
 void KeyboardInputMapper::reset() {
-    // Synthesize key up event on reset if keys are currently down.
-    while (! mKeyDowns.isEmpty()) {
-        const KeyDown& keyDown = mKeyDowns.top();
+    for (;;) {
+        int32_t keyCode, scanCode;
+        { // acquire lock
+            AutoMutex _l(mLock);
+
+            // Synthesize key up event on reset if keys are currently down.
+            if (mLocked.keyDowns.isEmpty()) {
+                initializeLocked();
+                break; // done
+            }
+
+            const KeyDown& keyDown = mLocked.keyDowns.top();
+            keyCode = keyDown.keyCode;
+            scanCode = keyDown.scanCode;
+        } // release lock
+
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0);
+        processKey(when, false, keyCode, scanCode, 0);
     }
 
     InputMapper::reset();
-
-    // Reinitialize.
-    initialize();
     getContext()->updateGlobalMetaState();
 }
 
@@ -768,56 +778,76 @@
         || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI);
 }
 
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
-        uint32_t policyFlags) {
-    if (down) {
-        // Rotate key codes according to orientation.
-        if (mAssociatedDisplayId >= 0) {
-            int32_t orientation;
-            if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
-                return;
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
+        int32_t scanCode, uint32_t policyFlags) {
+    int32_t newMetaState;
+    nsecs_t downTime;
+    bool metaStateChanged = false;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        if (down) {
+            // Rotate key codes according to orientation if needed.
+            // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
+            if (mAssociatedDisplayId >= 0) {
+                int32_t orientation;
+                if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+                    return;
+                }
+
+                keyCode = rotateKeyCode(keyCode, orientation);
             }
 
-            keyCode = rotateKeyCode(keyCode, orientation);
+            // Add key down.
+            ssize_t keyDownIndex = findKeyDownLocked(scanCode);
+            if (keyDownIndex >= 0) {
+                // key repeat, be sure to use same keycode as before in case of rotation
+                keyCode = mLocked.keyDowns.top().keyCode;
+            } else {
+                // key down
+                mLocked.keyDowns.push();
+                KeyDown& keyDown = mLocked.keyDowns.editTop();
+                keyDown.keyCode = keyCode;
+                keyDown.scanCode = scanCode;
+            }
+
+            mLocked.downTime = when;
+        } else {
+            // Remove key down.
+            ssize_t keyDownIndex = findKeyDownLocked(scanCode);
+            if (keyDownIndex >= 0) {
+                // key up, be sure to use same keycode as before in case of rotation
+                keyCode = mLocked.keyDowns.top().keyCode;
+                mLocked.keyDowns.removeAt(size_t(keyDownIndex));
+            } else {
+                // key was not actually down
+                LOGI("Dropping key up from device %s because the key was not down.  "
+                        "keyCode=%d, scanCode=%d",
+                        getDeviceName().string(), keyCode, scanCode);
+                return;
+            }
         }
 
-        // Add key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key repeat, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.top().keyCode;
-        } else {
-            // key down
-            mKeyDowns.push();
-            KeyDown& keyDown = mKeyDowns.editTop();
-            keyDown.keyCode = keyCode;
-            keyDown.scanCode = scanCode;
+        int32_t oldMetaState = mLocked.metaState;
+        newMetaState = updateMetaState(keyCode, down, oldMetaState);
+        if (oldMetaState != newMetaState) {
+            mLocked.metaState = newMetaState;
+            metaStateChanged = true;
         }
-    } else {
-        // Remove key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key up, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.top().keyCode;
-            mKeyDowns.removeAt(size_t(keyDownIndex));
-        } else {
-            // key was not actually down
-            LOGI("Dropping key up from device %s because the key was not down.  "
-                    "keyCode=%d, scanCode=%d",
-                    getDeviceName().string(), keyCode, scanCode);
-            return;
-        }
-    }
 
-    int32_t oldMetaState = mMetaState;
-    int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
-    if (oldMetaState != newMetaState) {
-        mMetaState = newMetaState;
+        downTime = mLocked.downTime;
+    } // release lock
+
+    if (metaStateChanged) {
         getContext()->updateGlobalMetaState();
     }
 
-    /* Apply policy. */
+    applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime);
+}
 
+void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down,
+        int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
     int32_t policyActions = getPolicy()->interceptKey(when,
             getDeviceId(), down, keyCode, scanCode, policyFlags);
 
@@ -825,30 +855,20 @@
         return; // event dropped
     }
 
-    /* Enqueue key event for dispatch. */
-
-    int32_t keyEventAction;
-    if (down) {
-        mDownTime = when;
-        keyEventAction = AKEY_EVENT_ACTION_DOWN;
-    } else {
-        keyEventAction = AKEY_EVENT_ACTION_UP;
-    }
-
+    int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
     int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
     if (policyFlags & POLICY_FLAG_WOKE_HERE) {
         keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
     }
 
     getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-            keyEventAction, keyEventFlags, keyCode, scanCode,
-            mMetaState, mDownTime);
+            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
 }
 
-ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
-    size_t n = mKeyDowns.size();
+ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) {
+    size_t n = mLocked.keyDowns.size();
     for (size_t i = 0; i < n; i++) {
-        if (mKeyDowns[i].scanCode == scanCode) {
+        if (mLocked.keyDowns[i].scanCode == scanCode) {
             return i;
         }
     }
@@ -869,7 +889,10 @@
 }
 
 int32_t KeyboardInputMapper::getMetaState() {
-    return mMetaState;
+    { // acquire lock
+        AutoMutex _l(mLock);
+        return mLocked.metaState;
+    } // release lock
 }
 
 
@@ -882,7 +905,7 @@
     mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
     mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
 
-    initialize();
+    initializeLocked();
 }
 
 TrackballInputMapper::~TrackballInputMapper() {
@@ -899,26 +922,33 @@
     info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
 }
 
-void TrackballInputMapper::initialize() {
+void TrackballInputMapper::initializeLocked() {
     mAccumulator.clear();
 
-    mDown = false;
-    mDownTime = 0;
+    mLocked.down = false;
+    mLocked.downTime = 0;
 }
 
 void TrackballInputMapper::reset() {
-    // Synthesize trackball button up event on reset if trackball button is currently down.
-    if (mDown) {
+    for (;;) {
+        { // acquire lock
+            AutoMutex _l(mLock);
+
+            if (! mLocked.down) {
+                initializeLocked();
+                break; // done
+            }
+        } // release lock
+
+        // Synthesize trackball button up event on reset.
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+        mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
         mAccumulator.btnMouse = false;
         sync(when);
+        mAccumulator.clear();
     }
 
     InputMapper::reset();
-
-    // Reinitialize.
-    initialize();
 }
 
 void TrackballInputMapper::process(const RawEvent* rawEvent) {
@@ -962,33 +992,79 @@
 }
 
 void TrackballInputMapper::sync(nsecs_t when) {
-    /* Get display properties so for rotation based on display orientation. */
+    int motionEventAction;
+    PointerCoords pointerCoords;
+    nsecs_t downTime;
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    int32_t orientation;
-    if (mAssociatedDisplayId >= 0) {
-        if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
-            return;
+        uint32_t fields = mAccumulator.fields;
+        bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
+
+        if (downChanged) {
+            if (mAccumulator.btnMouse) {
+                mLocked.down = true;
+                mLocked.downTime = when;
+            } else {
+                mLocked.down = false;
+            }
         }
-    } else {
-        orientation = InputReaderPolicyInterface::ROTATION_0;
-    }
 
-    /* Update saved trackball state */
+        downTime = mLocked.downTime;
+        float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f;
+        float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
 
-    uint32_t fields = mAccumulator.fields;
-    bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
-
-    if (downChanged) {
-        if (mAccumulator.btnMouse) {
-            mDown = true;
-            mDownTime = when;
+        if (downChanged) {
+            motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
         } else {
-            mDown = false;
+            motionEventAction = AMOTION_EVENT_ACTION_MOVE;
         }
-    }
 
-    /* Apply policy */
+        pointerCoords.x = x;
+        pointerCoords.y = y;
+        pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f;
+        pointerCoords.size = 0;
+        pointerCoords.touchMajor = 0;
+        pointerCoords.touchMinor = 0;
+        pointerCoords.toolMajor = 0;
+        pointerCoords.toolMinor = 0;
+        pointerCoords.orientation = 0;
 
+        if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) {
+            // Rotate motion based on display orientation if needed.
+            // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
+            int32_t orientation;
+            if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+                return;
+            }
+
+            float temp;
+            switch (orientation) {
+            case InputReaderPolicyInterface::ROTATION_90:
+                temp = pointerCoords.x;
+                pointerCoords.x = pointerCoords.y;
+                pointerCoords.y = - temp;
+                break;
+
+            case InputReaderPolicyInterface::ROTATION_180:
+                pointerCoords.x = - pointerCoords.x;
+                pointerCoords.y = - pointerCoords.y;
+                break;
+
+            case InputReaderPolicyInterface::ROTATION_270:
+                temp = pointerCoords.x;
+                pointerCoords.x = - pointerCoords.y;
+                pointerCoords.y = temp;
+                break;
+            }
+        }
+    } // release lock
+
+    applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
+}
+
+void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
+        PointerCoords* pointerCoords, nsecs_t downTime) {
     uint32_t policyFlags = 0;
     int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
 
@@ -996,62 +1072,24 @@
         return; // event dropped
     }
 
-    /* Enqueue motion event for dispatch. */
-
-    int32_t motionEventAction;
-    if (downChanged) {
-        motionEventAction = mDown ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-    } else {
-        motionEventAction = AMOTION_EVENT_ACTION_MOVE;
-    }
-
-    int32_t pointerId = 0;
-    PointerCoords pointerCoords;
-    pointerCoords.x = fields & Accumulator::FIELD_REL_X
-            ? mAccumulator.relX * mXScale : 0;
-    pointerCoords.y = fields & Accumulator::FIELD_REL_Y
-            ? mAccumulator.relY * mYScale : 0;
-    pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
-    pointerCoords.size = 0;
-    pointerCoords.touchMajor = 0;
-    pointerCoords.touchMinor = 0;
-    pointerCoords.toolMajor = 0;
-    pointerCoords.toolMinor = 0;
-    pointerCoords.orientation = 0;
-
-    float temp;
-    switch (orientation) {
-    case InputReaderPolicyInterface::ROTATION_90:
-        temp = pointerCoords.x;
-        pointerCoords.x = pointerCoords.y;
-        pointerCoords.y = - temp;
-        break;
-
-    case InputReaderPolicyInterface::ROTATION_180:
-        pointerCoords.x = - pointerCoords.x;
-        pointerCoords.y = - pointerCoords.y;
-        break;
-
-    case InputReaderPolicyInterface::ROTATION_270:
-        temp = pointerCoords.x;
-        pointerCoords.x = - pointerCoords.y;
-        pointerCoords.y = temp;
-        break;
-    }
-
     int32_t metaState = mContext->getGlobalMetaState();
+    int32_t pointerId = 0;
+
     getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
             motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            1, & pointerId, & pointerCoords, mXPrecision, mYPrecision, mDownTime);
+            1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
 }
 
 
 // --- TouchInputMapper ---
 
 TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
-        InputMapper(device), mAssociatedDisplayId(associatedDisplayId),
-        mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) {
-    initialize();
+        InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+    mLocked.surfaceOrientation = -1;
+    mLocked.surfaceWidth = -1;
+    mLocked.surfaceHeight = -1;
+
+    initializeLocked();
 }
 
 TouchInputMapper::~TouchInputMapper() {
@@ -1064,26 +1102,29 @@
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    // FIXME: Should ensure the surface information is up to date so that orientation changes
-    // are noticed immediately.  Unfortunately we will need to add some extra locks here
-    // to prevent race conditions.
-    // configureSurface();
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    info->addMotionRange(AINPUT_MOTION_RANGE_X, mOrientedRanges.x);
-    info->addMotionRange(AINPUT_MOTION_RANGE_Y, mOrientedRanges.y);
-    info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mOrientedRanges.pressure);
-    info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mOrientedRanges.size);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mOrientedRanges.touchMajor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mOrientedRanges.touchMinor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mOrientedRanges.toolMajor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mOrientedRanges.toolMinor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mOrientedRanges.orientation);
+        // Ensure surface information is up to date so that orientation changes are
+        // noticed immediately.
+        configureSurfaceLocked();
+
+        info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x);
+        info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y);
+        info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure);
+        info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation);
+    } // release lock
 }
 
-void TouchInputMapper::initialize() {
+void TouchInputMapper::initializeLocked() {
+    mCurrentTouch.clear();
     mLastTouch.clear();
     mDownTime = 0;
-    mCurrentVirtualKey.down = false;
 
     for (uint32_t i = 0; i < MAX_POINTERS; i++) {
         mAveragingTouchFilter.historyStart[i] = 0;
@@ -1091,6 +1132,8 @@
     }
 
     mJumpyTouchFilter.jumpyPointsDropped = 0;
+
+    mLocked.currentVirtualKey.down = false;
 }
 
 void TouchInputMapper::configure() {
@@ -1104,48 +1147,52 @@
     // Configure absolute axis information.
     configureAxes();
 
-    // Configure pressure factors.
-    if (mAxes.pressure.valid) {
-        mPressureOrigin = mAxes.pressure.minValue;
-        mPressureScale = 1.0f / mAxes.pressure.getRange();
-    } else {
-        mPressureOrigin = 0;
-        mPressureScale = 1.0f;
-    }
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    mOrientedRanges.pressure.min = 0.0f;
-    mOrientedRanges.pressure.max = 1.0f;
-    mOrientedRanges.pressure.flat = 0.0f;
-    mOrientedRanges.pressure.fuzz = mPressureScale;
+        // Configure pressure factors.
+        if (mAxes.pressure.valid) {
+            mLocked.pressureOrigin = mAxes.pressure.minValue;
+            mLocked.pressureScale = 1.0f / mAxes.pressure.getRange();
+        } else {
+            mLocked.pressureOrigin = 0;
+            mLocked.pressureScale = 1.0f;
+        }
 
-    // Configure size factors.
-    if (mAxes.size.valid) {
-        mSizeOrigin = mAxes.size.minValue;
-        mSizeScale = 1.0f / mAxes.size.getRange();
-    } else {
-        mSizeOrigin = 0;
-        mSizeScale = 1.0f;
-    }
+        mLocked.orientedRanges.pressure.min = 0.0f;
+        mLocked.orientedRanges.pressure.max = 1.0f;
+        mLocked.orientedRanges.pressure.flat = 0.0f;
+        mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale;
 
-    mOrientedRanges.size.min = 0.0f;
-    mOrientedRanges.size.max = 1.0f;
-    mOrientedRanges.size.flat = 0.0f;
-    mOrientedRanges.size.fuzz = mSizeScale;
+        // Configure size factors.
+        if (mAxes.size.valid) {
+            mLocked.sizeOrigin = mAxes.size.minValue;
+            mLocked.sizeScale = 1.0f / mAxes.size.getRange();
+        } else {
+            mLocked.sizeOrigin = 0;
+            mLocked.sizeScale = 1.0f;
+        }
 
-    // Configure orientation factors.
-    if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
-        mOrientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
-    } else {
-        mOrientationScale = 0.0f;
-    }
+        mLocked.orientedRanges.size.min = 0.0f;
+        mLocked.orientedRanges.size.max = 1.0f;
+        mLocked.orientedRanges.size.flat = 0.0f;
+        mLocked.orientedRanges.size.fuzz = mLocked.sizeScale;
 
-    mOrientedRanges.orientation.min = - M_PI_2;
-    mOrientedRanges.orientation.max = M_PI_2;
-    mOrientedRanges.orientation.flat = 0;
-    mOrientedRanges.orientation.fuzz = mOrientationScale;
+        // Configure orientation factors.
+        if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
+            mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
+        } else {
+            mLocked.orientationScale = 0.0f;
+        }
 
-    // Configure surface dimensions and orientation.
-    configureSurface();
+        mLocked.orientedRanges.orientation.min = - M_PI_2;
+        mLocked.orientedRanges.orientation.max = M_PI_2;
+        mLocked.orientedRanges.orientation.flat = 0;
+        mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale;
+
+        // Configure surface dimensions and orientation.
+        configureSurfaceLocked();
+    } // release lock
 }
 
 void TouchInputMapper::configureAxes() {
@@ -1160,11 +1207,12 @@
     mAxes.orientation.valid = false;
 }
 
-bool TouchInputMapper::configureSurface() {
+bool TouchInputMapper::configureSurfaceLocked() {
     // Update orientation and dimensions if needed.
     int32_t orientation;
     int32_t width, height;
     if (mAssociatedDisplayId >= 0) {
+        // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
         if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
             return false;
         }
@@ -1174,150 +1222,152 @@
         height = mAxes.y.getRange();
     }
 
-    bool orientationChanged = mSurfaceOrientation != orientation;
+    bool orientationChanged = mLocked.surfaceOrientation != orientation;
     if (orientationChanged) {
-        mSurfaceOrientation = orientation;
+        mLocked.surfaceOrientation = orientation;
     }
 
-    bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
+    bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
     if (sizeChanged) {
-        mSurfaceWidth = width;
-        mSurfaceHeight = height;
+        mLocked.surfaceWidth = width;
+        mLocked.surfaceHeight = height;
 
         // Compute size-dependent translation and scaling factors and place virtual keys.
         if (mAxes.x.valid && mAxes.y.valid) {
-            mXOrigin = mAxes.x.minValue;
-            mYOrigin = mAxes.y.minValue;
+            mLocked.xOrigin = mAxes.x.minValue;
+            mLocked.yOrigin = mAxes.y.minValue;
 
             LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
                     getDeviceId(), getDeviceName().string());
 
-            mXScale = float(width) / mAxes.x.getRange();
-            mYScale = float(height) / mAxes.y.getRange();
-            mXPrecision = 1.0f / mXScale;
-            mYPrecision = 1.0f / mYScale;
+            mLocked.xScale = float(width) / mAxes.x.getRange();
+            mLocked.yScale = float(height) / mAxes.y.getRange();
+            mLocked.xPrecision = 1.0f / mLocked.xScale;
+            mLocked.yPrecision = 1.0f / mLocked.yScale;
 
-            configureVirtualKeys();
+            configureVirtualKeysLocked();
         } else {
-            mXOrigin = 0;
-            mYOrigin = 0;
-            mXScale = 1.0f;
-            mYScale = 1.0f;
-            mXPrecision = 1.0f;
-            mYPrecision = 1.0f;
+            mLocked.xOrigin = 0;
+            mLocked.yOrigin = 0;
+            mLocked.xScale = 1.0f;
+            mLocked.yScale = 1.0f;
+            mLocked.xPrecision = 1.0f;
+            mLocked.yPrecision = 1.0f;
         }
 
         // Configure touch and tool area ranges.
         float diagonal = sqrt(float(width * width + height * height));
-        float diagonalFuzz = sqrt(mXScale * mXScale + mYScale * mYScale);
+        float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale
+                + mLocked.yScale * mLocked.yScale);
 
-        mOrientedRanges.touchMajor.min = 0.0f;
-        mOrientedRanges.touchMajor.max = diagonal;
-        mOrientedRanges.touchMajor.flat = 0.0f;
-        mOrientedRanges.touchMajor.fuzz = diagonalFuzz;
-        mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
+        InputDeviceInfo::MotionRange area;
+        area.min = 0.0f;
+        area.max = diagonal;
+        area.flat = 0.0f;
+        area.fuzz = diagonalFuzz;
 
-        mOrientedRanges.toolMinor = mOrientedRanges.toolMajor = mOrientedRanges.touchMajor;
+        mLocked.orientedRanges.touchMajor = area;
+        mLocked.orientedRanges.touchMinor = area;
+
+        mLocked.orientedRanges.toolMajor = area;
+        mLocked.orientedRanges.toolMinor = area;
     }
 
     if (orientationChanged || sizeChanged) {
         // Compute oriented surface dimensions, precision, and scales.
         float orientedXScale, orientedYScale;
-        switch (mSurfaceOrientation) {
+        switch (mLocked.surfaceOrientation) {
         case InputReaderPolicyInterface::ROTATION_90:
         case InputReaderPolicyInterface::ROTATION_270:
-            mOrientedSurfaceWidth = mSurfaceHeight;
-            mOrientedSurfaceHeight = mSurfaceWidth;
-            mOrientedXPrecision = mYPrecision;
-            mOrientedYPrecision = mXPrecision;
-            orientedXScale = mYScale;
-            orientedYScale = mXScale;
+            mLocked.orientedSurfaceWidth = mLocked.surfaceHeight;
+            mLocked.orientedSurfaceHeight = mLocked.surfaceWidth;
+            mLocked.orientedXPrecision = mLocked.yPrecision;
+            mLocked.orientedYPrecision = mLocked.xPrecision;
+            orientedXScale = mLocked.yScale;
+            orientedYScale = mLocked.xScale;
             break;
         default:
-            mOrientedSurfaceWidth = mSurfaceWidth;
-            mOrientedSurfaceHeight = mSurfaceHeight;
-            mOrientedXPrecision = mXPrecision;
-            mOrientedYPrecision = mYPrecision;
-            orientedXScale = mXScale;
-            orientedYScale = mYScale;
+            mLocked.orientedSurfaceWidth = mLocked.surfaceWidth;
+            mLocked.orientedSurfaceHeight = mLocked.surfaceHeight;
+            mLocked.orientedXPrecision = mLocked.xPrecision;
+            mLocked.orientedYPrecision = mLocked.yPrecision;
+            orientedXScale = mLocked.xScale;
+            orientedYScale = mLocked.yScale;
             break;
         }
 
         // Configure position ranges.
-        mOrientedRanges.x.min = 0;
-        mOrientedRanges.x.max = mOrientedSurfaceWidth;
-        mOrientedRanges.x.flat = 0;
-        mOrientedRanges.x.fuzz = orientedXScale;
+        mLocked.orientedRanges.x.min = 0;
+        mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth;
+        mLocked.orientedRanges.x.flat = 0;
+        mLocked.orientedRanges.x.fuzz = orientedXScale;
 
-        mOrientedRanges.y.min = 0;
-        mOrientedRanges.y.max = mOrientedSurfaceHeight;
-        mOrientedRanges.y.flat = 0;
-        mOrientedRanges.y.fuzz = orientedYScale;
+        mLocked.orientedRanges.y.min = 0;
+        mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight;
+        mLocked.orientedRanges.y.flat = 0;
+        mLocked.orientedRanges.y.fuzz = orientedYScale;
     }
 
     return true;
 }
 
-void TouchInputMapper::configureVirtualKeys() {
+void TouchInputMapper::configureVirtualKeysLocked() {
     assert(mAxes.x.valid && mAxes.y.valid);
 
+    // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
     Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
     getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
 
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    mLocked.virtualKeys.clear();
 
-        mVirtualKeys.clear();
+    if (virtualKeyDefinitions.size() == 0) {
+        return;
+    }
 
-        if (virtualKeyDefinitions.size() == 0) {
-            return;
+    mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size());
+
+    int32_t touchScreenLeft = mAxes.x.minValue;
+    int32_t touchScreenTop = mAxes.y.minValue;
+    int32_t touchScreenWidth = mAxes.x.getRange();
+    int32_t touchScreenHeight = mAxes.y.getRange();
+
+    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
+        const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+                virtualKeyDefinitions[i];
+
+        mLocked.virtualKeys.add();
+        VirtualKey& virtualKey = mLocked.virtualKeys.editTop();
+
+        virtualKey.scanCode = virtualKeyDefinition.scanCode;
+        int32_t keyCode;
+        uint32_t flags;
+        if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
+                & keyCode, & flags)) {
+            LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+            mLocked.virtualKeys.pop(); // drop the key
+            continue;
         }
 
-        mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
+        virtualKey.keyCode = keyCode;
+        virtualKey.flags = flags;
 
-        int32_t touchScreenLeft = mAxes.x.minValue;
-        int32_t touchScreenTop = mAxes.y.minValue;
-        int32_t touchScreenWidth = mAxes.x.getRange();
-        int32_t touchScreenHeight = mAxes.y.getRange();
+        // convert the key definition's display coordinates into touch coordinates for a hit box
+        int32_t halfWidth = virtualKeyDefinition.width / 2;
+        int32_t halfHeight = virtualKeyDefinition.height / 2;
 
-        for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
-            const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
-                    virtualKeyDefinitions[i];
+        virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
+                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
+        virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
+                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
+        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
+                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
+        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
+                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
 
-            mVirtualKeys.add();
-            VirtualKey& virtualKey = mVirtualKeys.editTop();
-
-            virtualKey.scanCode = virtualKeyDefinition.scanCode;
-            int32_t keyCode;
-            uint32_t flags;
-            if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
-                    & keyCode, & flags)) {
-                LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
-                mVirtualKeys.pop(); // drop the key
-                continue;
-            }
-
-            virtualKey.keyCode = keyCode;
-            virtualKey.flags = flags;
-
-            // convert the key definition's display coordinates into touch coordinates for a hit box
-            int32_t halfWidth = virtualKeyDefinition.width / 2;
-            int32_t halfHeight = virtualKeyDefinition.height / 2;
-
-            virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
-                    * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-            virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
-                    * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-            virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
-                    * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-            virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
-                    * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-
-            LOGI("  VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
-                    virtualKey.scanCode, virtualKey.keyCode,
-                    virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
-        }
-    } // release virtual key lock
+        LOGI("  VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
+                virtualKey.scanCode, virtualKey.keyCode,
+                virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+    }
 }
 
 void TouchInputMapper::reset() {
@@ -1329,20 +1379,16 @@
         syncTouch(when, true);
     }
 
-    InputMapper::reset();
+    { // acquire lock
+        AutoMutex _l(mLock);
+        initializeLocked();
+    } // release lock
 
-    // Reinitialize.
-    initialize();
+    InputMapper::reset();
 }
 
 void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
-    /* Refresh associated display information and update our size configuration if needed. */
-
-    if (! configureSurface()) {
-        return;
-    }
-
-    /* Apply policy */
+    // Apply generic policy actions.
 
     uint32_t policyFlags = 0;
     int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
@@ -1352,7 +1398,7 @@
         return; // event dropped
     }
 
-    /* Preprocess pointer data */
+    // Preprocess pointer data.
 
     if (mParameters.useBadTouchFilter) {
         if (applyBadTouchFilter()) {
@@ -1381,14 +1427,14 @@
         savedTouch = & mCurrentTouch;
     }
 
-    /* Process touches and virtual keys */
+    // Process touches and virtual keys.
 
     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
     if (touchResult == DISPATCH_TOUCH) {
         dispatchTouches(when, policyFlags);
     }
 
-    /* Copy current touch to last touch in preparation for the next cycle. */
+    // Copy current touch to last touch in preparation for the next cycle.
 
     if (touchResult == DROP_STROKE) {
         mLastTouch.clear();
@@ -1403,13 +1449,19 @@
     int32_t keyCode, scanCode, downTime;
     TouchResult touchResult;
 
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down) {
+        // Update surface size and orientation, including virtual key positions.
+        if (! configureSurfaceLocked()) {
+            return DROP_STROKE;
+        }
+
+        // Check for virtual key press.
+        if (mLocked.currentVirtualKey.down) {
             if (mCurrentTouch.pointerCount == 0) {
                 // Pointer went up while virtual key was down.
-                mCurrentVirtualKey.down = false;
+                mLocked.currentVirtualKey.down = false;
 #if DEBUG_VIRTUAL_KEYS
                 LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                         mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1423,8 +1475,8 @@
             if (mCurrentTouch.pointerCount == 1) {
                 int32_t x = mCurrentTouch.pointers[0].x;
                 int32_t y = mCurrentTouch.pointers[0].y;
-                const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
-                if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
+                const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y);
+                if (virtualKey && virtualKey->keyCode == mLocked.currentVirtualKey.keyCode) {
                     // Pointer is still within the space of the virtual key.
                     return SKIP_TOUCH;
                 }
@@ -1434,7 +1486,7 @@
             // Send key cancellation and drop the stroke so subsequent motions will be
             // considered fresh downs.  This is useful when the user swipes away from the
             // virtual key area into the main display surface.
-            mCurrentVirtualKey.down = false;
+            mLocked.currentVirtualKey.down = false;
 #if DEBUG_VIRTUAL_KEYS
             LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
                     mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1449,16 +1501,16 @@
                 // Pointer just went down.  Handle off-screen touches, if needed.
                 int32_t x = mCurrentTouch.pointers[0].x;
                 int32_t y = mCurrentTouch.pointers[0].y;
-                if (! isPointInsideSurface(x, y)) {
+                if (! isPointInsideSurfaceLocked(x, y)) {
                     // If exactly one pointer went down, check for virtual key hit.
                     // Otherwise we will drop the entire stroke.
                     if (mCurrentTouch.pointerCount == 1) {
-                        const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+                        const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y);
                         if (virtualKey) {
-                            mCurrentVirtualKey.down = true;
-                            mCurrentVirtualKey.downTime = when;
-                            mCurrentVirtualKey.keyCode = virtualKey->keyCode;
-                            mCurrentVirtualKey.scanCode = virtualKey->scanCode;
+                            mLocked.currentVirtualKey.down = true;
+                            mLocked.currentVirtualKey.downTime = when;
+                            mLocked.currentVirtualKey.keyCode = virtualKey->keyCode;
+                            mLocked.currentVirtualKey.scanCode = virtualKey->scanCode;
 #if DEBUG_VIRTUAL_KEYS
                             LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
                                     mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1478,12 +1530,20 @@
 
     DispatchVirtualKey:
         // Collect remaining state needed to dispatch virtual key.
-        keyCode = mCurrentVirtualKey.keyCode;
-        scanCode = mCurrentVirtualKey.scanCode;
-        downTime = mCurrentVirtualKey.downTime;
-    } // release virtual key lock
+        keyCode = mLocked.currentVirtualKey.keyCode;
+        scanCode = mLocked.currentVirtualKey.scanCode;
+        downTime = mLocked.currentVirtualKey.downTime;
+    } // release lock
 
     // Dispatch virtual key.
+    applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags,
+            keyCode, scanCode, downTime);
+    return touchResult;
+}
+
+void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
+        int32_t keyEventAction, int32_t keyEventFlags,
+        int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
     int32_t metaState = mContext->getGlobalMetaState();
 
     if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
@@ -1497,7 +1557,6 @@
         getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
                 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
     }
-    return touchResult;
 }
 
 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
@@ -1566,107 +1625,118 @@
     uint32_t pointerCount = 0;
     int32_t pointerIds[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
-
-    // Walk through the the active pointers and map touch screen coordinates (TouchData) into
-    // display coordinates (PointerCoords) and adjust for display orientation.
-    while (! idBits.isEmpty()) {
-        uint32_t id = idBits.firstMarkedBit();
-        idBits.clearBit(id);
-        uint32_t index = touch->idToIndex[id];
-
-        float x = float(touch->pointers[index].x - mXOrigin) * mXScale;
-        float y = float(touch->pointers[index].y - mYOrigin) * mYScale;
-        float pressure = float(touch->pointers[index].pressure - mPressureOrigin) * mPressureScale;
-        float size = float(touch->pointers[index].size - mSizeOrigin) * mSizeScale;
-
-        float orientation = float(touch->pointers[index].orientation) * mOrientationScale;
-
-        float touchMajor, touchMinor, toolMajor, toolMinor;
-        if (abs(orientation) <= M_PI_4) {
-            // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
-            touchMajor = float(touch->pointers[index].touchMajor) * mYScale;
-            touchMinor = float(touch->pointers[index].touchMinor) * mXScale;
-            toolMajor = float(touch->pointers[index].toolMajor) * mYScale;
-            toolMinor = float(touch->pointers[index].toolMinor) * mXScale;
-        } else {
-            // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
-            touchMajor = float(touch->pointers[index].touchMajor) * mXScale;
-            touchMinor = float(touch->pointers[index].touchMinor) * mYScale;
-            toolMajor = float(touch->pointers[index].toolMajor) * mXScale;
-            toolMinor = float(touch->pointers[index].toolMinor) * mYScale;
-        }
-
-        switch (mSurfaceOrientation) {
-        case InputReaderPolicyInterface::ROTATION_90: {
-            float xTemp = x;
-            x = y;
-            y = mSurfaceWidth - xTemp;
-            orientation -= M_PI_2;
-            if (orientation < - M_PI_2) {
-                orientation += M_PI;
-            }
-            break;
-        }
-        case InputReaderPolicyInterface::ROTATION_180: {
-            x = mSurfaceWidth - x;
-            y = mSurfaceHeight - y;
-            orientation = - orientation;
-            break;
-        }
-        case InputReaderPolicyInterface::ROTATION_270: {
-            float xTemp = x;
-            x = mSurfaceHeight - y;
-            y = xTemp;
-            orientation += M_PI_2;
-            if (orientation > M_PI_2) {
-                orientation -= M_PI;
-            }
-            break;
-        }
-        }
-
-        pointerIds[pointerCount] = int32_t(id);
-
-        pointerCoords[pointerCount].x = x;
-        pointerCoords[pointerCount].y = y;
-        pointerCoords[pointerCount].pressure = pressure;
-        pointerCoords[pointerCount].size = size;
-        pointerCoords[pointerCount].touchMajor = touchMajor;
-        pointerCoords[pointerCount].touchMinor = touchMinor;
-        pointerCoords[pointerCount].toolMajor = toolMajor;
-        pointerCoords[pointerCount].toolMinor = toolMinor;
-        pointerCoords[pointerCount].orientation = orientation;
-
-        if (id == changedId) {
-            motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-        }
-
-        pointerCount += 1;
-    }
-
-    // Check edge flags by looking only at the first pointer since the flags are
-    // global to the event.
     int32_t motionEventEdgeFlags = 0;
-    if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-        if (pointerCoords[0].x <= 0) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
-        } else if (pointerCoords[0].x >= mOrientedSurfaceWidth) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+    float xPrecision, yPrecision;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        // Walk through the the active pointers and map touch screen coordinates (TouchData) into
+        // display coordinates (PointerCoords) and adjust for display orientation.
+        while (! idBits.isEmpty()) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+            uint32_t index = touch->idToIndex[id];
+
+            float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale;
+            float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale;
+            float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin)
+                    * mLocked.pressureScale;
+            float size = float(touch->pointers[index].size - mLocked.sizeOrigin)
+                    * mLocked.sizeScale;
+
+            float orientation = float(touch->pointers[index].orientation)
+                    * mLocked.orientationScale;
+
+            float touchMajor, touchMinor, toolMajor, toolMinor;
+            if (abs(orientation) <= M_PI_4) {
+                // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
+                touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale;
+                touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale;
+                toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale;
+                toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale;
+            } else {
+                // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
+                touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale;
+                touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale;
+                toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale;
+                toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale;
+            }
+
+            switch (mLocked.surfaceOrientation) {
+            case InputReaderPolicyInterface::ROTATION_90: {
+                float xTemp = x;
+                x = y;
+                y = mLocked.surfaceWidth - xTemp;
+                orientation -= M_PI_2;
+                if (orientation < - M_PI_2) {
+                    orientation += M_PI;
+                }
+                break;
+            }
+            case InputReaderPolicyInterface::ROTATION_180: {
+                x = mLocked.surfaceWidth - x;
+                y = mLocked.surfaceHeight - y;
+                orientation = - orientation;
+                break;
+            }
+            case InputReaderPolicyInterface::ROTATION_270: {
+                float xTemp = x;
+                x = mLocked.surfaceHeight - y;
+                y = xTemp;
+                orientation += M_PI_2;
+                if (orientation > M_PI_2) {
+                    orientation -= M_PI;
+                }
+                break;
+            }
+            }
+
+            pointerIds[pointerCount] = int32_t(id);
+
+            pointerCoords[pointerCount].x = x;
+            pointerCoords[pointerCount].y = y;
+            pointerCoords[pointerCount].pressure = pressure;
+            pointerCoords[pointerCount].size = size;
+            pointerCoords[pointerCount].touchMajor = touchMajor;
+            pointerCoords[pointerCount].touchMinor = touchMinor;
+            pointerCoords[pointerCount].toolMajor = toolMajor;
+            pointerCoords[pointerCount].toolMinor = toolMinor;
+            pointerCoords[pointerCount].orientation = orientation;
+
+            if (id == changedId) {
+                motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+            }
+
+            pointerCount += 1;
         }
-        if (pointerCoords[0].y <= 0) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
-        } else if (pointerCoords[0].y >= mOrientedSurfaceHeight) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+
+        // Check edge flags by looking only at the first pointer since the flags are
+        // global to the event.
+        if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
+            if (pointerCoords[0].x <= 0) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
+            } else if (pointerCoords[0].x >= mLocked.orientedSurfaceWidth) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+            }
+            if (pointerCoords[0].y <= 0) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
+            } else if (pointerCoords[0].y >= mLocked.orientedSurfaceHeight) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+            }
         }
-    }
+
+        xPrecision = mLocked.orientedXPrecision;
+        yPrecision = mLocked.orientedYPrecision;
+    } // release lock
 
     getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
             motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
             pointerCount, pointerIds, pointerCoords,
-            mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+            xPrecision, yPrecision, mDownTime);
 }
 
-bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
     if (mAxes.x.valid && mAxes.y.valid) {
         return x >= mAxes.x.minValue && x <= mAxes.x.maxValue
                 && y >= mAxes.y.minValue && y <= mAxes.y.maxValue;
@@ -1674,9 +1744,11 @@
     return true;
 }
 
-const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLvk(int32_t x, int32_t y) {
-    for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked(
+        int32_t x, int32_t y) {
+    size_t numVirtualKeys = mLocked.virtualKeys.size();
+    for (size_t i = 0; i < numVirtualKeys; i++) {
+        const VirtualKey& virtualKey = mLocked.virtualKeys[i];
 
 #if DEBUG_VIRTUAL_KEYS
         LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
@@ -2224,50 +2296,53 @@
 }
 
 int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
+        if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.keyCode == keyCode) {
             return AKEY_STATE_VIRTUAL;
         }
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
             if (virtualKey.keyCode == keyCode) {
                 return AKEY_STATE_UP;
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return AKEY_STATE_UNKNOWN;
 }
 
 int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
+        if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.scanCode == scanCode) {
             return AKEY_STATE_VIRTUAL;
         }
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
             if (virtualKey.scanCode == scanCode) {
                 return AKEY_STATE_UP;
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return AKEY_STATE_UNKNOWN;
 }
 
 bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
         const int32_t* keyCodes, uint8_t* outFlags) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
 
             for (size_t i = 0; i < numCodes; i++) {
                 if (virtualKey.keyCode == keyCodes[i]) {
@@ -2275,7 +2350,7 @@
                 }
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return true;
 }
@@ -2304,7 +2379,6 @@
 void SingleTouchInputMapper::reset() {
     TouchInputMapper::reset();
 
-    // Reinitialize.
     initialize();
  }
 
@@ -2436,7 +2510,6 @@
 void MultiTouchInputMapper::reset() {
     TouchInputMapper::reset();
 
-    // Reinitialize.
     initialize();
 }
 
diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/Equalizer.java
index 21c37bb..b062b64 100644
--- a/media/java/android/media/Equalizer.java
+++ b/media/java/android/media/Equalizer.java
@@ -182,9 +182,9 @@
         }
         int[] param = new int[1];
         param[0] = PARAM_NUM_BANDS;
-        short[] value = new short[1];
-        checkStatus(getParameter(param, value));
-        mNumBands = value[0];
+        short[] result = new short[1];
+        checkStatus(getParameter(param, result));
+        mNumBands = result[0];
         return mNumBands;
     }
 
@@ -199,16 +199,8 @@
      */
     public short[] getBandLevelRange()
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
-        int[] param = new int[1];
-        int[] value = new int[2];
-        param[0] = PARAM_LEVEL_RANGE;
-        checkStatus(getParameter(param, value));
-
         short[] result = new short[2];
-
-        result[0] = (short)value[0];
-        result[1] = (short)value[1];
-
+        checkStatus(getParameter(PARAM_LEVEL_RANGE, result));
         return result;
     }
 
@@ -222,14 +214,14 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public void setBandLevel(int band, short level)
+    public void setBandLevel(short band, short level)
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         int[] param = new int[2];
-        int[] value = new int[1];
+        short[] value = new short[1];
 
         param[0] = PARAM_BAND_LEVEL;
-        param[1] = band;
-        value[0] = (int)level;
+        param[1] = (int)band;
+        value[0] = level;
         checkStatus(setParameter(param, value));
     }
 
@@ -242,16 +234,16 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public short getBandLevel(int band)
+    public short getBandLevel(short band)
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         int[] param = new int[2];
-        int[] result = new int[1];
+        short[] result = new short[1];
 
         param[0] = PARAM_BAND_LEVEL;
-        param[1] = band;
+        param[1] = (int)band;
         checkStatus(getParameter(param, result));
 
-        return (short)result[0];
+        return result[0];
     }
 
 
@@ -264,13 +256,13 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public int getCenterFreq(int band)
+    public int getCenterFreq(short band)
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         int[] param = new int[2];
         int[] result = new int[1];
 
         param[0] = PARAM_CENTER_FREQ;
-        param[1] = band;
+        param[1] = (int)band;
         checkStatus(getParameter(param, result));
 
         return result[0];
@@ -286,12 +278,12 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public int[] getBandFreqRange(int band)
+    public int[] getBandFreqRange(short band)
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         int[] param = new int[2];
         int[] result = new int[2];
         param[0] = PARAM_BAND_FREQ_RANGE;
-        param[1] = band;
+        param[1] = (int)band;
         checkStatus(getParameter(param, result));
 
         return result;
@@ -305,10 +297,10 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public int getBand(int frequency)
+    public short getBand(int frequency)
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         int[] param = new int[2];
-        int[] result = new int[1];
+        short[] result = new short[1];
 
         param[0] = PARAM_GET_BAND;
         param[1] = frequency;
@@ -326,11 +318,9 @@
      */
     public short getCurrentPreset()
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
-        int[] param = new int[1];
-        param[0] = PARAM_CURRENT_PRESET;
-        short[] value = new short[1];
-        checkStatus(getParameter(param, value));
-        return value[0];
+        short[] result = new short[1];
+        checkStatus(getParameter(PARAM_CURRENT_PRESET, result));
+        return result[0];
     }
 
     /**
@@ -356,11 +346,9 @@
      */
     public short getNumberOfPresets()
     throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
-        int[] param = new int[1];
-        param[0] = PARAM_GET_NUM_OF_PRESETS;
-        short[] value = new short[1];
-        checkStatus(getParameter(param, value));
-        return value[0];
+        short[] result = new short[1];
+        checkStatus(getParameter(PARAM_GET_NUM_OF_PRESETS, result));
+        return result[0];
     }
 
     /**
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 4c3ebca..a70bdff 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1848,6 +1848,8 @@
     case EQ_PARAM_NUM_BANDS:
     case EQ_PARAM_CUR_PRESET:
     case EQ_PARAM_GET_NUM_OF_PRESETS:
+    case EQ_PARAM_BAND_LEVEL:
+    case EQ_PARAM_GET_BAND:
         if (*pValueSize < sizeof(int16_t)) {
             LOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
             return -EINVAL;
@@ -1856,6 +1858,13 @@
         break;
 
     case EQ_PARAM_LEVEL_RANGE:
+        if (*pValueSize < 2 * sizeof(int16_t)) {
+            LOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
+            return -EINVAL;
+        }
+        *pValueSize = 2 * sizeof(int16_t);
+        break;
+
     case EQ_PARAM_BAND_FREQ_RANGE:
         if (*pValueSize < 2 * sizeof(int32_t)) {
             LOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 2  %d", *pValueSize);
@@ -1863,8 +1872,7 @@
         }
         *pValueSize = 2 * sizeof(int32_t);
         break;
-    case EQ_PARAM_BAND_LEVEL:
-    case EQ_PARAM_GET_BAND:
+
     case EQ_PARAM_CENTER_FREQ:
         if (*pValueSize < sizeof(int32_t)) {
             LOGV("\tLVM_ERROR : Equalizer_getParameter() invalid pValueSize 1  %d", *pValueSize);
@@ -1891,13 +1899,13 @@
 
     switch (param) {
     case EQ_PARAM_NUM_BANDS:
-        *(int16_t *)pValue = FIVEBAND_NUMBANDS;
+        *(uint16_t *)pValue = (uint16_t)FIVEBAND_NUMBANDS;
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
         break;
 
     case EQ_PARAM_LEVEL_RANGE:
-        *(int32_t *)pValue = -1500;
-        *((int32_t *)pValue + 1) = 1500;
+        *(int16_t *)pValue = -1500;
+        *((int16_t *)pValue + 1) = 1500;
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d",
         //      *(int32_t *)pValue, *((int32_t *)pValue + 1));
         break;
@@ -1908,7 +1916,7 @@
             status = -EINVAL;
             break;
         }
-        *(int32_t *)pValue = EqualizerGetBandLevel(pContext, param2);
+        *(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d",
         //      param2, *(int32_t *)pValue);
         break;
@@ -1937,18 +1945,18 @@
 
     case EQ_PARAM_GET_BAND:
         param2 = *pParam;
-        *(int32_t *)pValue = EqualizerGetBand(pContext, param2);
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetBand(pContext, param2);
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d",
         //      param2, *(int32_t *)pValue);
         break;
 
     case EQ_PARAM_CUR_PRESET:
-        *(int16_t *)pValue = EqualizerGetPreset(pContext);
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetPreset(pContext);
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
         break;
 
     case EQ_PARAM_GET_NUM_OF_PRESETS:
-        *(int16_t *)pValue = EqualizerGetNumPresets();
+        *(uint16_t *)pValue = (uint16_t)EqualizerGetNumPresets();
         //LOGV("\tEqualizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
         break;
 
@@ -1968,12 +1976,12 @@
         break;
 
     case EQ_PARAM_PROPERTIES: {
-        uint16_t *p = (uint16_t *)pValue;
+        int16_t *p = (int16_t *)pValue;
         LOGV("\tEqualizer_getParameter() EQ_PARAM_PROPERTIES");
-        p[0] = EqualizerGetPreset(pContext);
-        p[1] = FIVEBAND_NUMBANDS;
+        p[0] = (int16_t)EqualizerGetPreset(pContext);
+        p[1] = (int16_t)FIVEBAND_NUMBANDS;
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
-            p[2 + i] = EqualizerGetBandLevel(pContext, i);
+            p[2 + i] = (int16_t)EqualizerGetBandLevel(pContext, i);
         }
     } break;
 
@@ -2011,7 +2019,7 @@
     //LOGV("\tEqualizer_setParameter start");
     switch (param) {
     case EQ_PARAM_CUR_PRESET:
-        preset = *(int16_t *)pValue;
+        preset = (int32_t)(*(uint16_t *)pValue);
 
         //LOGV("\tEqualizer_setParameter() EQ_PARAM_CUR_PRESET %d", preset);
         if ((preset >= EqualizerGetNumPresets())||(preset < 0)) {
@@ -2022,7 +2030,7 @@
         break;
     case EQ_PARAM_BAND_LEVEL:
         band =  *pParam;
-        level = *(int32_t *)pValue;
+        level = (int32_t)(*(int16_t *)pValue);
         //LOGV("\tEqualizer_setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
         if (band >= FIVEBAND_NUMBANDS) {
             status = -EINVAL;
@@ -2030,8 +2038,28 @@
         }
         EqualizerSetBandLevel(pContext, band, level);
         break;
+    case EQ_PARAM_PROPERTIES: {
+        //LOGV("\tEqualizer_setParameter() EQ_PARAM_PROPERTIES");
+        int16_t *p = (int16_t *)pValue;
+        if ((int)p[0] >= EqualizerGetNumPresets()) {
+            status = -EINVAL;
+            break;
+        }
+        if (p[0] >= 0) {
+            EqualizerSetPreset(pContext, (int)p[0]);
+        } else {
+            if ((int)p[1] != FIVEBAND_NUMBANDS) {
+                status = -EINVAL;
+                break;
+            }
+            for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+                EqualizerSetBandLevel(pContext, i, (int)p[2 + i]);
+            }
+        }
+    } break;
     default:
         LOGV("\tLVM_ERROR : setParameter() invalid param %d", param);
+        status = -EINVAL;
         break;
     }
 
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index a71f236..f8e4357 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -350,6 +350,8 @@
     case EQ_PARAM_NUM_BANDS:
     case EQ_PARAM_CUR_PRESET:
     case EQ_PARAM_GET_NUM_OF_PRESETS:
+    case EQ_PARAM_BAND_LEVEL:
+    case EQ_PARAM_GET_BAND:
         if (*pValueSize < sizeof(int16_t)) {
             return -EINVAL;
         }
@@ -357,14 +359,19 @@
         break;
 
     case EQ_PARAM_LEVEL_RANGE:
+        if (*pValueSize < 2 * sizeof(int16_t)) {
+            return -EINVAL;
+        }
+        *pValueSize = 2 * sizeof(int16_t);
+        break;
+
     case EQ_PARAM_BAND_FREQ_RANGE:
         if (*pValueSize < 2 * sizeof(int32_t)) {
             return -EINVAL;
         }
         *pValueSize = 2 * sizeof(int32_t);
         break;
-    case EQ_PARAM_BAND_LEVEL:
-    case EQ_PARAM_GET_BAND:
+
     case EQ_PARAM_CENTER_FREQ:
         if (*pValueSize < sizeof(int32_t)) {
             return -EINVAL;
@@ -375,19 +382,26 @@
     case EQ_PARAM_GET_PRESET_NAME:
         break;
 
+    case EQ_PARAM_PROPERTIES:
+        if (*pValueSize < (2 + kNumBands) * sizeof(uint16_t)) {
+            return -EINVAL;
+        }
+        *pValueSize = (2 + kNumBands) * sizeof(uint16_t);
+        break;
+
     default:
         return -EINVAL;
     }
 
     switch (param) {
     case EQ_PARAM_NUM_BANDS:
-        *(int16_t *)pValue = kNumBands;
+        *(uint16_t *)pValue = (uint16_t)kNumBands;
         LOGV("Equalizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
         break;
 
     case EQ_PARAM_LEVEL_RANGE:
-        *(int32_t *)pValue = -9600;
-        *((int32_t *)pValue + 1) = 4800;
+        *(int16_t *)pValue = -9600;
+        *((int16_t *)pValue + 1) = 4800;
         LOGV("Equalizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d", *(int32_t *)pValue, *((int32_t *)pValue + 1));
         break;
 
@@ -397,7 +411,7 @@
             status = -EINVAL;
             break;
         }
-        *(int32_t *)pValue = pEqualizer->getGain(param2);
+        *(int16_t *)pValue = (int16_t)pEqualizer->getGain(param2);
         LOGV("Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", param2, *(int32_t *)pValue);
         break;
 
@@ -423,17 +437,17 @@
 
     case EQ_PARAM_GET_BAND:
         param2 = *pParam;
-        *(int32_t *)pValue = pEqualizer->getMostRelevantBand(param2);
+        *(uint16_t *)pValue = (uint16_t)pEqualizer->getMostRelevantBand(param2);
         LOGV("Equalizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d", param2, *(int32_t *)pValue);
         break;
 
     case EQ_PARAM_CUR_PRESET:
-        *(int16_t *)pValue = pEqualizer->getPreset();
+        *(uint16_t *)pValue = (uint16_t)pEqualizer->getPreset();
         LOGV("Equalizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
         break;
 
     case EQ_PARAM_GET_NUM_OF_PRESETS:
-        *(int16_t *)pValue = pEqualizer->getNumPresets();
+        *(uint16_t *)pValue = (uint16_t)pEqualizer->getNumPresets();
         LOGV("Equalizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
         break;
 
@@ -450,6 +464,16 @@
         LOGV("Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d", param2, gEqualizerPresets[param2].name, *pValueSize);
         break;
 
+    case EQ_PARAM_PROPERTIES: {
+        int16_t *p = (int16_t *)pValue;
+        LOGV("Equalizer_getParameter() EQ_PARAM_PROPERTIES");
+        p[0] = (int16_t)pEqualizer->getPreset();
+        p[1] = (int16_t)kNumBands;
+        for (int i = 0; i < kNumBands; i++) {
+            p[2 + i] = (int16_t)pEqualizer->getGain(i);
+        }
+    } break;
+
     default:
         LOGV("Equalizer_getParameter() invalid param %d", param);
         status = -EINVAL;
@@ -489,10 +513,10 @@
 
     switch (param) {
     case EQ_PARAM_CUR_PRESET:
-        preset = *(int16_t *)pValue;
+        preset = (int32_t)(*(uint16_t *)pValue);
 
         LOGV("setParameter() EQ_PARAM_CUR_PRESET %d", preset);
-        if (preset >= pEqualizer->getNumPresets()) {
+        if (preset < 0 || preset >= pEqualizer->getNumPresets()) {
             status = -EINVAL;
             break;
         }
@@ -501,7 +525,7 @@
         break;
     case EQ_PARAM_BAND_LEVEL:
         band =  *pParam;
-        level = *(int32_t *)pValue;
+        level = (int32_t)(*(int16_t *)pValue);
         LOGV("setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
         if (band >= kNumBands) {
             status = -EINVAL;
@@ -510,8 +534,29 @@
         pEqualizer->setGain(band, level);
         pEqualizer->commit(true);
        break;
+    case EQ_PARAM_PROPERTIES: {
+        LOGV("setParameter() EQ_PARAM_PROPERTIES");
+        int16_t *p = (int16_t *)pValue;
+        if ((int)p[0] >= pEqualizer->getNumPresets()) {
+            status = -EINVAL;
+            break;
+        }
+        if (p[0] >= 0) {
+            pEqualizer->setPreset((int)p[0]);
+        } else {
+            if ((int)p[1] != kNumBands) {
+                status = -EINVAL;
+                break;
+            }
+            for (int i = 0; i < kNumBands; i++) {
+                pEqualizer->setGain(i, (int32_t)p[2 + i]);
+            }
+        }
+        pEqualizer->commit(true);
+    } break;
     default:
         LOGV("setParameter() invalid param %d", param);
+        status = -EINVAL;
         break;
     }
 
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 9fe207c..4eb63e8 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, 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.
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index fef3e6e..73862c3 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -1,5 +1,5 @@
 /*
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, 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.
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index d12e558..1d1913d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, 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.
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f26676d..c40d285 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -344,7 +344,7 @@
 
 status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
-    if (timeUs <= 1000000LL) {  // XXX: 1 second
+    if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
         LOGE("Max file duration is too short: %lld us", timeUs);
         return BAD_VALUE;
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index baf9f4f..9f712c3 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1615,6 +1615,16 @@
                         mOwner->write(kData2, sizeof(kData2));
 
                     mOwner->endBox();  // esds
+                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
+                             !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+                    // 3gpp2 Spec AMRSampleEntry fields
+                    mOwner->beginBox("damr");
+                      mOwner->writeCString("   ");  // vendor: 4 bytes
+                      mOwner->writeInt8(0);         // decoder version
+                      mOwner->writeInt16(0x83FF);   // mode set: all enabled
+                      mOwner->writeInt8(0);         // mode change period
+                      mOwner->writeInt8(1);         // frames per sample
+                    mOwner->endBox();
                   }
                 mOwner->endBox();
             } else {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index e1fc4e7..db534e0 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -149,3 +149,7 @@
     return static_cast<Sensor const*>(sensor)->getResolution();
 }
 
+int ASensor_getMinDelay(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getMinDelay();
+}
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index 00d95d8..b4ce024 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -121,6 +121,7 @@
         float           temperature;
         float           distance;
         float           light;
+        float           pressure;
     };
     int32_t reserved1[4];
 } ASensorEvent;
@@ -188,7 +189,8 @@
 /*
  * Sets the delivery rate of events in microseconds for the given sensor.
  * Note that this is a hint only, generally event will arrive at a higher
- * rate.
+ * rate. It is an error to set a rate inferior to the value returned by
+ * ASensor_getMinDelay().
  * Returns a negative error code on failure.
  */
 int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
@@ -239,6 +241,13 @@
  */
 float ASensor_getResolution(ASensor const* sensor);
 
+/*
+ * Returns the minimum delay allowed between events in microseconds.
+ * A value of zero means that this sensor doesn't report events at a
+ * constant rate, but rather only when a new data is available.
+ */
+int ASensor_getMinDelay(ASensor const* sensor);
+
 
 #ifdef __cplusplus
 };
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 8abd6499..b5c018f 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -6,9 +6,6 @@
 
 include $(CLEAR_VARS)
 
-# Set to 1 to use gralloc and copybits
-LIBAGL_USE_GRALLOC_COPYBITS := 1
-
 LOCAL_SRC_FILES:= \
 	egl.cpp                     \
 	state.cpp		            \
@@ -51,13 +48,6 @@
     LOCAL_C_INCLUDES += bionic/libc/private
 endif
 
-ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
-    LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
-    LOCAL_SRC_FILES += copybit.cpp
-    LOCAL_SHARED_LIBRARIES += libui
-endif
-
-
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
 LOCAL_MODULE:= libGLES_android
 
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index 255ccac..bbb82fc 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -55,9 +55,6 @@
     memset(crop_rect, 0, sizeof(crop_rect));
     generate_mipmap = GL_FALSE;
     direct = GL_FALSE;
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    try_copybit = false;
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
     buffer = 0;
 }
 
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 279e040..70e3bef 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -80,9 +80,6 @@
     GLint               crop_rect[4];
     GLint               generate_mipmap;
     GLint               direct;
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    bool                try_copybit;
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
     android_native_buffer_t* buffer;
 };
 
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 71825c5..4997dc8 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -26,9 +26,6 @@
 #include "primitives.h"
 #include "texture.h"
 #include "BufferObjectManager.h"
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-#include "copybit.h"
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
 
 // ----------------------------------------------------------------------------
 
@@ -707,12 +704,6 @@
 
 void drawPrimitivesTriangleFan(ogles_context_t* c,
         GLint first, GLsizei count) {
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    if (drawTriangleFanWithCopybit(c, first, count)) {
-        return;
-    }
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
     drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
 }
 
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
deleted file mode 100644
index 67d1ce7..0000000
--- a/opengl/libagl/copybit.cpp
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
-**
-** Copyright 2009, 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.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "context.h"
-#include "fp.h"
-#include "state.h"
-#include "matrix.h"
-#include "vertex.h"
-#include "light.h"
-#include "primitives.h"
-#include "texture.h"
-#include "BufferObjectManager.h"
-#include "TextureObjectManager.h"
-
-#include <hardware/gralloc.h>
-#include <hardware/copybit.h>
-#include <private/ui/android_natives_priv.h>
-
-#include <ui/GraphicBuffer.h>
-#include <ui/Region.h>
-#include <ui/Rect.h>
-
-
-#define DEBUG_COPYBIT false
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-static void textureToCopyBitImage(
-        const GGLSurface* surface, int32_t opFormat, 
-        android_native_buffer_t* buffer, copybit_image_t* img)
-{
-    img->w      = surface->stride;
-    img->h      = surface->height;
-    img->format = opFormat;
-    img->base   = surface->data;
-    img->handle = (native_handle_t *)buffer->handle;
-}
-
-struct clipRectRegion : public copybit_region_t {
-    clipRectRegion(ogles_context_t* c) 
-    {
-        scissor_t const* scissor = &c->rasterizer.state.scissor;
-        r.l = scissor->left;
-        r.t = scissor->top;
-        r.r = scissor->right;
-        r.b = scissor->bottom;
-        next = iterate; 
-    }
-private:
-    static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
-        *rect = static_cast<clipRectRegion const*>(self)->r;
-        const_cast<copybit_region_t *>(self)->next = iterate_done;
-        return 1;
-    }
-    static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
-        return 0;
-    }
-public:
-    copybit_rect_t r;
-};
-
-static bool supportedCopybitsFormat(int format) {
-    switch (format) {
-    case COPYBIT_FORMAT_RGBA_8888:
-    case COPYBIT_FORMAT_RGBX_8888:
-    case COPYBIT_FORMAT_RGB_888:
-    case COPYBIT_FORMAT_RGB_565:
-    case COPYBIT_FORMAT_BGRA_8888:
-    case COPYBIT_FORMAT_RGBA_5551:
-    case COPYBIT_FORMAT_RGBA_4444:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static bool hasAlpha(int format) {
-    switch (format) {
-    case COPYBIT_FORMAT_RGBA_8888:
-    case COPYBIT_FORMAT_BGRA_8888:
-    case COPYBIT_FORMAT_RGBA_5551:
-    case COPYBIT_FORMAT_RGBA_4444:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static inline int fixedToByte(GGLfixed val) {
-    return (val - (val >> 8)) >> 8;
-}
-
-/**
- * Performs a quick check of the rendering state. If this function returns
- * false we cannot use the copybit driver.
- */
-
-static bool checkContext(ogles_context_t* c) {
-
-	// By convention copybitQuickCheckContext() has already returned true.
-	// avoid checking the same information again.
-	
-    if (c->copybits.blitEngine == NULL) {
-        LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
-        return false;
-    }
-
-    if (c->rasterizer.state.enables
-                    & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
-        LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
-        return false;
-    }
-
-    // Note: The drawSurfaceBuffer is only set for destination
-    // surfaces types that are supported by the hardware and
-    // do not have an alpha channel. So we don't have to re-check that here.
-
-    static const int tmu = 0;
-    texture_unit_t& u(c->textures.tmu[tmu]);
-    EGLTextureObject* textureObject = u.texture;
-
-    if (!supportedCopybitsFormat(textureObject->surface.format)) {
-        LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
-        return false;
-    }
-    return true;
-}
-
-
-static bool copybit(GLint x, GLint y,
-        GLint w, GLint h,
-        EGLTextureObject* textureObject,
-        const GLint* crop_rect,
-        int transform,
-        ogles_context_t* c)
-{
-    status_t err = NO_ERROR;
-
-    // We assume checkContext has already been called and has already
-    // returned true.
-
-    const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
-
-    y = cbSurface.height - (y + h);
-
-    const GLint Ucr = crop_rect[0];
-    const GLint Vcr = crop_rect[1];
-    const GLint Wcr = crop_rect[2];
-    const GLint Hcr = crop_rect[3];
-
-    GLint screen_w = w;
-    GLint screen_h = h;
-    int32_t dsdx = Wcr << 16;   // dsdx =  ((Wcr/screen_w)/Wt)*Wt
-    int32_t dtdy = Hcr << 16;   // dtdy = -((Hcr/screen_h)/Ht)*Ht
-    if (transform & COPYBIT_TRANSFORM_ROT_90) {
-        swap(screen_w, screen_h);
-    }
-    if (dsdx!=screen_w || dtdy!=screen_h) {
-        // in most cases the divide is not needed
-        dsdx /= screen_w;
-        dtdy /= screen_h;
-    }
-    dtdy = -dtdy; // see equation of dtdy above
-
-    // copybit doesn't say anything about filtering, so we can't
-    // discriminate. On msm7k, copybit will always filter.
-    // the code below handles min/mag filters, we keep it as a reference.
-    
-#ifdef MIN_MAG_FILTER
-    int32_t texelArea = gglMulx(dtdy, dsdx);
-    if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
-        // Non-linear filtering on a texture enlargement.
-        LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
-        return false;
-    }
-    if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
-        // Non-linear filtering on an texture shrink.
-        LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
-        return false;
-    }
-#endif
-    
-    const uint32_t enables = c->rasterizer.state.enables;
-    int planeAlpha = 255;
-    bool alphaPlaneWorkaround = false;
-    static const int tmu = 0;
-    texture_t& tev(c->rasterizer.state.texture[tmu]);
-    int32_t opFormat = textureObject->surface.format;
-    const bool srcTextureHasAlpha = hasAlpha(opFormat);
-    if (!srcTextureHasAlpha) {
-        planeAlpha = fixedToByte(c->currentColorClamped.a);
-    }
-
-    const bool cbHasAlpha = hasAlpha(cbSurface.format);
-    bool blending = false;
-    if ((enables & GGL_ENABLE_BLENDING)
-            && !(c->rasterizer.state.blend.src == GL_ONE
-                    && c->rasterizer.state.blend.dst == GL_ZERO)) {
-        // Blending is OK if it is
-        // the exact kind of blending that the copybits hardware supports.
-        // Note: The hardware only supports
-        // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
-        // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
-        // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
-        // because the performance is worth it, even if the results are
-        // not correct.
-        if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
-                || c->rasterizer.state.blend.src == GL_ONE)
-                && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
-                && c->rasterizer.state.blend.alpha_separate == 0)) {
-            // Incompatible blend mode.
-            LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
-            return false;
-        }
-        blending = true;
-    } else {
-        if (cbHasAlpha) {
-            // NOTE: the result will be slightly wrong in this case because
-            // the destination alpha channel will be set to 1.0 instead of
-            // the iterated alpha value. *shrug*.
-        }
-        // disable plane blending and src blending for supported formats
-        planeAlpha = 255;
-        if (opFormat == COPYBIT_FORMAT_RGBA_8888) {
-            opFormat = COPYBIT_FORMAT_RGBX_8888;
-        } else {
-            if (srcTextureHasAlpha) {
-                LOGD_IF(DEBUG_COPYBIT, "texture format requires blending");
-                return false;
-            }
-        }
-    }
-
-    switch (tev.env) {
-    case GGL_REPLACE:
-        break;
-    case GGL_MODULATE:
-        // only cases allowed is:
-        // RGB  source, color={1,1,1,a} -> can be done with GL_REPLACE
-        // RGBA source, color={1,1,1,1} -> can be done with GL_REPLACE
-        if (blending) {
-            if (c->currentColorClamped.r == c->currentColorClamped.a &&
-                c->currentColorClamped.g == c->currentColorClamped.a &&
-                c->currentColorClamped.b == c->currentColorClamped.a) {
-                // TODO: RGBA source, color={1,1,1,a} / regular-blending
-                // is equivalent
-                alphaPlaneWorkaround = true;
-                break;
-            }
-        }
-        LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE");
-        return false;
-    default:
-        // Incompatible texture environment.
-        LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
-        return false;
-    }
-
-    copybit_device_t* copybit = c->copybits.blitEngine;
-    copybit_image_t src;
-    textureToCopyBitImage(&textureObject->surface, opFormat,
-            textureObject->buffer, &src);
-    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
-
-    /*
-     *  Below we perform extra passes needed to emulate things the h/w
-     * cannot do.
-     */
-
-    const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
-    const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
-
-    sp<GraphicBuffer> tempBitmap;
-
-    if (dsdx < maxScaleInv || dsdx > minScaleInv ||
-        dtdy < maxScaleInv || dtdy > minScaleInv)
-    {
-        // The requested scale is out of the range the hardware
-        // can support.
-        LOGD_IF(DEBUG_COPYBIT,
-                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
-                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
-                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
-
-        int32_t xscale=0x10000, yscale=0x10000;
-        if (dsdx > minScaleInv)         xscale = c->copybits.minScale;
-        else if (dsdx < maxScaleInv)    xscale = c->copybits.maxScale;
-        if (dtdy > minScaleInv)         yscale = c->copybits.minScale;
-        else if (dtdy < maxScaleInv)    yscale = c->copybits.maxScale;
-        dsdx = gglMulx(dsdx, xscale);
-        dtdy = gglMulx(dtdy, yscale);
-
-        /* we handle only one step of resizing below. Handling an arbitrary
-         * number is relatively easy (replace "if" above by "while"), but requires
-         * two intermediate buffers and so far we never had the need.
-         */
-
-        if (dsdx < maxScaleInv || dsdx > minScaleInv ||
-            dtdy < maxScaleInv || dtdy > minScaleInv) {
-            LOGD_IF(DEBUG_COPYBIT,
-                    "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
-                    "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
-                    dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
-            return false;
-        }
-
-        const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
-        const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
-
-        LOGD_IF(DEBUG_COPYBIT,
-                "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
-                xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
-
-        tempBitmap = new GraphicBuffer(
-                    tmp_w, tmp_h, src.format,
-                    GraphicBuffer::USAGE_HW_2D);
-
-        err = tempBitmap->initCheck();
-        if (err == NO_ERROR) {
-            copybit_image_t tmp_dst;
-            copybit_rect_t tmp_rect;
-            tmp_dst.w = tmp_w;
-            tmp_dst.h = tmp_h;
-            tmp_dst.format = tempBitmap->format;
-            tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
-            tmp_rect.l = 0;
-            tmp_rect.t = 0;
-            tmp_rect.r = tmp_dst.w;
-            tmp_rect.b = tmp_dst.h;
-            region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
-            err = copybit->stretch(copybit,
-                    &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
-            src = tmp_dst;
-            srect = tmp_rect;
-        }
-    }
-
-    copybit_image_t dst;
-    textureToCopyBitImage(&cbSurface, cbSurface.format,
-            c->copybits.drawSurfaceBuffer, &dst);
-    copybit_rect_t drect = {x, y, x+w, y+h};
-
-
-    /* and now the alpha-plane hack. This handles the "Fade" case of a
-     * texture with an alpha channel.
-     */
-    if (alphaPlaneWorkaround) {
-        sp<GraphicBuffer> tempCb = new GraphicBuffer(
-                    w, h, COPYBIT_FORMAT_RGB_565,
-                    GraphicBuffer::USAGE_HW_2D);
-
-        err = tempCb->initCheck();
-
-        copybit_image_t tmpCbImg;
-        copybit_rect_t tmpCbRect;
-        copybit_rect_t tmpdrect = drect;
-        tmpCbImg.w = w;
-        tmpCbImg.h = h;
-        tmpCbImg.format = tempCb->format;
-        tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle;
-        tmpCbRect.l = 0;
-        tmpCbRect.t = 0;
-
-        if (drect.l < 0) {
-            tmpCbRect.l = -tmpdrect.l;
-            tmpdrect.l = 0;
-        }
-        if (drect.t < 0) {
-            tmpCbRect.t = -tmpdrect.t;
-            tmpdrect.t = 0;
-        }
-        if (drect.l + tmpCbImg.w > dst.w) {
-            tmpCbImg.w = dst.w - drect.l;
-            tmpdrect.r = dst.w;
-        }
-        if (drect.t + tmpCbImg.h > dst.h) {
-            tmpCbImg.h = dst.h - drect.t;
-            tmpdrect.b = dst.h;
-        }
-
-        tmpCbRect.r = tmpCbImg.w;
-        tmpCbRect.b = tmpCbImg.h;
-
-        if (!err) {
-            // first make a copy of the destination buffer
-            region_iterator tmp_it(Region(Rect(w, h)));
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
-            err = copybit->stretch(copybit,
-                    &tmpCbImg, &dst, &tmpCbRect, &tmpdrect, &tmp_it);
-        }
-        if (!err) {
-            // then proceed as usual, but without the alpha plane
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-            copybit->set_parameter(copybit, COPYBIT_DITHER,
-                    (enables & GGL_ENABLE_DITHER) ?
-                            COPYBIT_ENABLE : COPYBIT_DISABLE);
-            clipRectRegion it(c);
-            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
-        }
-        if (!err) {
-            // finally copy back the destination on top with 1-alphaplane
-            int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a);
-            clipRectRegion it(c);
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-            err = copybit->stretch(copybit,
-                    &dst, &tmpCbImg, &tmpdrect, &tmpCbRect, &it);
-        }
-    } else {
-        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
-        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
-        copybit->set_parameter(copybit, COPYBIT_DITHER,
-                (enables & GGL_ENABLE_DITHER) ?
-                        COPYBIT_ENABLE : COPYBIT_DISABLE);
-        clipRectRegion it(c);
-
-        LOGD_IF(0,
-             "dst={%d, %d, %d, %p, %p}, "
-             "src={%d, %d, %d, %p, %p}, "
-             "drect={%d,%d,%d,%d}, "
-             "srect={%d,%d,%d,%d}, "
-             "it={%d,%d,%d,%d}, " ,
-             dst.w, dst.h, dst.format, dst.base, dst.handle,
-             src.w, src.h, src.format, src.base, src.handle,
-             drect.l, drect.t, drect.r, drect.b,
-             srect.l, srect.t, srect.r, srect.b,
-             it.r.l, it.r.t, it.r.r, it.r.b
-        );
-
-        err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
-    }
-    if (err != NO_ERROR) {
-        c->textures.tmu[0].texture->try_copybit = false;
-    }
-    return err == NO_ERROR ? true : false;
-}
-
-/*
- * Try to draw a triangle fan with copybit, return false if we fail.
- */
-bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
-{
-    if (!checkContext(c)) {
-        return false;
-    }
-
-    // FIXME: we should handle culling  here
-    c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
-
-    // we detect if we're dealing with a rectangle, by comparing the
-    // rectangles {v0,v2} and {v1,v3} which should be identical.
-    
-    // NOTE: we should check that the rectangle is window aligned, however
-    // if we do that, the optimization won't be taken in a lot of cases.
-    // Since this code is intended to be used with SurfaceFlinger only,
-    // so it's okay...
-    
-    const vec4_t& v0 = c->vc.vBuffer[0].window;
-    const vec4_t& v1 = c->vc.vBuffer[1].window;
-    const vec4_t& v2 = c->vc.vBuffer[2].window;
-    const vec4_t& v3 = c->vc.vBuffer[3].window;
-    int l = min(v0.x, v2.x);
-    int b = min(v0.y, v2.y);
-    int r = max(v0.x, v2.x);
-    int t = max(v0.y, v2.y);
-    if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
-        (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
-        LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
-        return false;
-    }
-
-    // fetch and transform texture coordinates
-    // NOTE: maybe it would be better to have a "compileElementsAll" method
-    // that would ensure all vertex data are fetched and transformed
-    const transform_t& tr = c->transforms.texture[0].transform; 
-    for (size_t i=0 ; i<4 ; i++) {
-        const GLubyte* tp = c->arrays.texture[0].element(i);
-        vertex_t* const v = &c->vc.vBuffer[i];
-        c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
-        // FIXME: we should bail if q!=1
-        c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
-    }
-    
-    const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
-    const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
-    const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
-    const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
-    int txl = min(t0.x, t2.x);
-    int txb = min(t0.y, t2.y);
-    int txr = max(t0.x, t2.x);
-    int txt = max(t0.y, t2.y);
-    if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
-        (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
-        LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
-        return false;
-    }
-    if ((txl != 0) || (txb != 0) ||
-        (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
-        // we could probably handle this case, if we wanted to
-        LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
-                txl, txb, txr, txt);
-        return false;
-    }
-
-    // at this point, we know we are dealing with a rectangle, so we 
-    // only need to consider 3 vertices for computing the jacobians
-    
-    const int dx01 = v1.x - v0.x;
-    const int dx02 = v2.x - v0.x;
-    const int dy01 = v1.y - v0.y;
-    const int dy02 = v2.y - v0.y;
-    const int ds01 = t1.S - t0.S;
-    const int ds02 = t2.S - t0.S;
-    const int dt01 = t1.T - t0.T;
-    const int dt02 = t2.T - t0.T;
-    const int area = dx01*dy02 - dy01*dx02;
-    int dsdx, dsdy, dtdx, dtdy;
-    if (area >= 0) {
-        dsdx = ds01*dy02 - ds02*dy01;
-        dtdx = dt01*dy02 - dt02*dy01;
-        dsdy = ds02*dx01 - ds01*dx02;
-        dtdy = dt02*dx01 - dt01*dx02;
-    } else {
-        dsdx = ds02*dy01 - ds01*dy02;
-        dtdx = dt02*dy01 - dt01*dy02;
-        dsdy = ds01*dx02 - ds02*dx01;
-        dtdy = dt01*dx02 - dt02*dx01;
-    }
-
-    // here we rely on the fact that we know the transform is
-    // a rigid-body transform AND that it can only rotate in 90 degrees
-    // increments
-
-    int transform = 0;
-    if (dsdx == 0) {
-        // 90 deg rotation case
-        // [ 0    dtdx  ]
-        // [ dsdx    0  ]
-        transform |= COPYBIT_TRANSFORM_ROT_90;
-        // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
-        if (dtdx > 0)
-            transform |= COPYBIT_TRANSFORM_FLIP_H;
-        if (dsdy < 0)
-            transform |= COPYBIT_TRANSFORM_FLIP_V;
-    } else {
-        // [ dsdx    0  ]
-        // [ 0     dtdy ]
-        if (dsdx < 0)
-            transform |= COPYBIT_TRANSFORM_FLIP_H;
-        if (dtdy < 0)
-            transform |= COPYBIT_TRANSFORM_FLIP_V;
-    }
-
-    //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
-    //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
-    //      dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
-
-    int x = l >> 4;
-    int y = b >> 4;
-    int w = (r-l) >> 4;
-    int h = (t-b) >> 4;
-    texture_unit_t& u(c->textures.tmu[0]);
-    EGLTextureObject* textureObject = u.texture;
-    GLint tWidth = textureObject->surface.width;
-    GLint tHeight = textureObject->surface.height;
-    GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
-    const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
-    y = cbSurface.height - (y + h);
-    return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
-}
-
-/*
- * Try to drawTexiOESWithCopybit, return false if we fail.
- */
-
-bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
-        GLint w, GLint h, ogles_context_t* c)
-{
-    // quickly process empty rects
-    if ((w|h) <= 0) {
-        return true;
-    }
-    if (!checkContext(c)) {
-        return false;
-    }
-    texture_unit_t& u(c->textures.tmu[0]);
-    EGLTextureObject* textureObject = u.texture;
-    return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
-}
-
-} // namespace android
-
diff --git a/opengl/libagl/copybit.h b/opengl/libagl/copybit.h
deleted file mode 100644
index b8b5afd..0000000
--- a/opengl/libagl/copybit.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
-**
-** Copyright 2009, 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.
-*/
-
-#ifndef ANDROID_OPENGLES_COPYBIT_H
-#define ANDROID_OPENGLES_COPYBIT_H
-
-#include <stdlib.h>
-
-#include <GLES/gl.h>
-
-#include "TextureObjectManager.h"
-namespace android {
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-
-bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
-        GLint w, GLint h, ogles_context_t* c);
-
-bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first,
-        GLsizei count);
-
-inline bool copybitQuickCheckContext(ogles_context_t* c) {
-        return  c->copybits.drawSurfaceBuffer != 0
-            && c->rasterizer.state.enabled_tmu == 1
-            && c->textures.tmu[0].texture->try_copybit;
-}
-
-/*
- * Tries to draw a drawTexiOES using copybit hardware.
- * Returns true if successful.
- */
-inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z,
-        GLint w, GLint h, ogles_context_t* c) {
-    if (!copybitQuickCheckContext(c)) {
-    	return false;
-   	}
-   	
-   	return drawTexiOESWithCopybit_impl(x, y, z, w, h, c);
-}
-
-/*
- * Tries to draw a triangle fan using copybit hardware.
- * Returns true if successful.
- */
-inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first,
-        GLsizei count) {
-    /*
-     * We are looking for the glDrawArrays call made by SurfaceFlinger.
-     */
-
-    if ((count!=4) || first || !copybitQuickCheckContext(c))
-        return false;
-    
-    return drawTriangleFanWithCopybit_impl(c, first, count);
-}
-
-
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
-} // namespace android
-
-#endif // ANDROID_OPENGLES_COPYBIT_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 54d7307..5bbe441 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -628,23 +628,6 @@
     return buffer;
 }
 
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-
-static bool supportedCopybitsDestinationFormat(int format) {
-    // Hardware supported
-    switch (format) {
-    case HAL_PIXEL_FORMAT_RGB_565:
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-    case HAL_PIXEL_FORMAT_RGBA_4444:
-    case HAL_PIXEL_FORMAT_RGBA_5551:
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-        return true;
-    }
-    return false;
-}
-#endif
-
 EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
 {
     GGLSurface buffer;
@@ -658,18 +641,6 @@
     if (depth.data != gl->rasterizer.state.buffers.depth.data)
         gl->rasterizer.procs.depthBuffer(gl, &depth);
 
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    gl->copybits.drawSurfaceBuffer = 0;
-    if (gl->copybits.blitEngine != NULL) {
-        if (supportedCopybitsDestinationFormat(buffer.format)) {
-            buffer_handle_t handle = this->buffer->handle;
-            if (handle != NULL) {
-                gl->copybits.drawSurfaceBuffer = this->buffer;
-            }
-        }
-    }
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
     return EGL_TRUE;
 }
 EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 27bb545..a0f720a 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -28,10 +28,6 @@
 #include "BufferObjectManager.h"
 #include "TextureObjectManager.h"
 
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-#include <hardware/copybit.h>
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -101,35 +97,6 @@
     // OpenGL enables dithering by default
     c->rasterizer.procs.enable(c, GL_DITHER);
 
-    c->copybits.blitEngine = NULL;
-    c->copybits.minScale = 0;
-    c->copybits.maxScale = 0;
-    c->copybits.drawSurfaceBuffer = 0;
-
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    hw_module_t const* module;
-    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
-        struct copybit_device_t* copyBits;
-        if (copybit_open(module, &copyBits) == 0) {
-            c->copybits.blitEngine = copyBits;
-            {
-                int minLim = copyBits->get(copyBits,
-                        COPYBIT_MINIFICATION_LIMIT);
-                if (minLim != -EINVAL && minLim > 0) {
-                    c->copybits.minScale = (1 << 16) / minLim;
-                }
-            }
-            {
-                int magLim = copyBits->get(copyBits,
-                        COPYBIT_MAGNIFICATION_LIMIT);
-                if (magLim != -EINVAL && magLim > 0) {
-                    c->copybits.maxScale = min(32*1024-1, magLim) << 16;
-                }
-            }
-        }
-    }
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
     return c;
 }
 
@@ -144,11 +111,6 @@
     c->bufferObjectManager->decStrong(c);
     ggl_uninit_context(&(c->rasterizer));
     free(c->rasterizer.base);
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    if (c->copybits.blitEngine != NULL) {
-        copybit_close((struct copybit_device_t*) c->copybits.blitEngine);
-    }
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
 }
 
 void _ogles_error(ogles_context_t* c, GLenum error)
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index d67612e..eb96895 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -26,10 +26,6 @@
 #include <private/ui/android_natives_priv.h>
 #include <ETC1/etc1.h>
 
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-#include "copybit.h"
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
-
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -763,17 +759,10 @@
 static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
         ogles_context_t* c)
 {
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
-            gglFixedToIntRound(y), gglFixedToIntRound(z),
-            gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
-        return;
-    }
-#else
     // quickly reject empty rects
     if ((w|h) <= 0)
         return;
-#endif
+
     drawTexxOESImp(x, y, z, w, h, c);
 }
 
@@ -785,11 +774,6 @@
     // which is a lot faster.
 
     if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-        if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
-            return;
-        }
-#endif
         const int tmu = 0;
         texture_unit_t& u(c->textures.tmu[tmu]);
         EGLTextureObject* textureObject = u.texture;
@@ -797,9 +781,7 @@
         const GLint Hcr = textureObject->crop_rect[3];
 
         if ((w == Wcr) && (h == -Hcr)) {
-#ifndef LIBAGL_USE_GRALLOC_COPYBITS
             if ((w|h) <= 0) return; // quickly reject empty rects
-#endif
 
             if (u.dirty) {
                 c->rasterizer.procs.activeTexture(c, tmu);
@@ -1646,13 +1628,6 @@
     // bind it to the texture unit
     sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
     tex->setImage(native_buffer);
-
-#ifdef LIBAGL_USE_GRALLOC_COPYBITS
-    tex->try_copybit = false;
-    if (c->copybits.blitEngine != NULL) {
-        tex->try_copybit = true;
-    }
-#endif // LIBAGL_USE_GRALLOC_COPYBITS
 }
 
 void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 714fd3e..665446a 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -42,7 +42,6 @@
 #include "egl_impl.h"
 #include "Loader.h"
 
-#define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
 
 // ----------------------------------------------------------------------------
@@ -143,6 +142,22 @@
 SortedVector<egl_object_t*> egl_object_t::sObjects;
 Mutex egl_object_t::sLock;
 
+
+struct egl_config_t {
+    egl_config_t() {}
+    egl_config_t(int impl, EGLConfig config)
+        : impl(impl), config(config), configId(0), implConfigId(0) { }
+    int         impl;           // the implementation this config is for
+    EGLConfig   config;         // the implementation's EGLConfig
+    EGLint      configId;       // our CONFIG_ID
+    EGLint      implConfigId;   // the implementation's CONFIG_ID
+    inline bool operator < (const egl_config_t& rhs) const {
+        if (impl < rhs.impl) return true;
+        if (impl > rhs.impl) return false;
+        return config < rhs.config;
+    }
+};
+
 struct egl_display_t {
     enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
     
@@ -163,13 +178,14 @@
         strings_t   queryString;
     };
 
-    uint32_t    magic;
-    DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
-    EGLint      numTotalConfigs;
-    uint32_t    refs;
-    Mutex       lock;
+    uint32_t        magic;
+    DisplayImpl     disp[IMPL_NUM_IMPLEMENTATIONS];
+    EGLint          numTotalConfigs;
+    egl_config_t*   configs;
+    uint32_t        refs;
+    Mutex           lock;
     
-    egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
+    egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
     ~egl_display_t() { magic = 0; }
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
@@ -179,14 +195,15 @@
 {
     typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
 
-    egl_surface_t(EGLDisplay dpy, EGLSurface surface,
+    egl_surface_t(EGLDisplay dpy, EGLSurface surface, EGLConfig config,
             int impl, egl_connection_t const* cnx) 
-    : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
+    : dpy(dpy), surface(surface), config(config), impl(impl), cnx(cnx) {
     }
     ~egl_surface_t() {
     }
     EGLDisplay                  dpy;
     EGLSurface                  surface;
+    EGLConfig                   config;
     int                         impl;
     egl_connection_t const*     cnx;
 };
@@ -195,7 +212,7 @@
 {
     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
     
-    egl_context_t(EGLDisplay dpy, EGLContext context,
+    egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
             int impl, egl_connection_t const* cnx, int version) 
     : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
       version(version)
@@ -203,6 +220,7 @@
     }
     EGLDisplay                  dpy;
     EGLContext                  context;
+    EGLConfig                   config;
     EGLSurface                  read;
     EGLSurface                  draw;
     int                         impl;
@@ -354,7 +372,7 @@
 {
     while (first <= last) {
         int mid = (first + last) / 2;
-        if (key > sortedArray[mid]) { 
+        if (sortedArray[mid] < key) {
             first = mid + 1;
         } else if (key < sortedArray[mid]) { 
             last = mid - 1;
@@ -365,26 +383,11 @@
     return -1;
 }
 
-static EGLint configToUniqueId(egl_display_t const* dp, int i, int index) 
-{
-    // NOTE: this mapping works only if we have no more than two EGLimpl
-    return (i>0 ? dp->disp[0].numConfigs : 0) + index;
-}
-
-static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
-        int& i, int& index) 
-{
-    // NOTE: this mapping works only if we have no more than two EGLimpl
-    size_t numConfigs = dp->disp[0].numConfigs;
-    i = configId / numConfigs;
-    index = configId % numConfigs;
-}
-
 static int cmp_configs(const void* a, const void *b)
 {
-    EGLConfig c0 = *(EGLConfig const *)a;
-    EGLConfig c1 = *(EGLConfig const *)b;
-    return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
+    const egl_config_t& c0 = *(egl_config_t const *)a;
+    const egl_config_t& c1 = *(egl_config_t const *)b;
+    return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
 }
 
 struct extention_map_t {
@@ -477,20 +480,15 @@
 
 static egl_connection_t* validate_display_config(
         EGLDisplay dpy, EGLConfig config,
-        egl_display_t const*& dp, int& impl, int& index)
+        egl_display_t const*& dp)
 {
     dp = get_display(dpy);
     if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
 
-    impl = uintptr_t(config)>>24;
-    if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
-        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
-    } 
-    index = uintptr_t(config) & 0xFFFFFF;
-    if (index >= dp->disp[impl].numConfigs) {
+    if (intptr_t(config) >= dp->numTotalConfigs) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     }
-    egl_connection_t* const cnx = &gEGLImpl[impl];
+    egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
     if (cnx->dso == 0) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     }
@@ -718,11 +716,6 @@
                             dp->disp[i].dpy, dp->disp[i].config, n,
                             &dp->disp[i].numConfigs))
                     {
-                        // sort the configurations so we can do binary searches
-                        qsort(  dp->disp[i].config,
-                                dp->disp[i].numConfigs,
-                                sizeof(EGLConfig), cmp_configs);
-
                         dp->numTotalConfigs += n;
                         res = EGL_TRUE;
                     }
@@ -732,6 +725,30 @@
     }
 
     if (res == EGL_TRUE) {
+        dp->configs = new egl_config_t[ dp->numTotalConfigs ];
+        for (int i=0, k=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+            egl_connection_t* const cnx = &gEGLImpl[i];
+            if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
+                for (int j=0 ; j<dp->disp[i].numConfigs ; j++) {
+                    dp->configs[k].impl = i;
+                    dp->configs[k].config = dp->disp[i].config[j];
+                    dp->configs[k].configId = k + 1; // CONFIG_ID start at 1
+                    // store the implementation's CONFIG_ID
+                    cnx->egl.eglGetConfigAttrib(
+                            dp->disp[i].dpy,
+                            dp->disp[i].config[j],
+                            EGL_CONFIG_ID,
+                            &dp->configs[k].implConfigId);
+                    k++;
+                }
+            }
+        }
+
+        // sort our configurations so we can do binary-searches
+        qsort(  dp->configs,
+                dp->numTotalConfigs,
+                sizeof(egl_config_t), cmp_configs);
+
         dp->refs++;
         if (major != NULL) *major = VERSION_MAJOR;
         if (minor != NULL) *minor = VERSION_MINOR;
@@ -784,6 +801,7 @@
     
     dp->refs--;
     dp->numTotalConfigs = 0;
+    delete [] dp->configs;
     clearTLS();
     return res;
 }
@@ -804,14 +822,13 @@
         *num_config = numConfigs;
         return EGL_TRUE;
     }
+
     GLint n = 0;
-    for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
-        for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
-            *configs++ = MAKE_CONFIG(j, i);
-            config_size--;
-            n++;
-        }
-    }    
+    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
+        *configs++ = EGLConfig(i);
+        config_size--;
+        n++;
+    }
     
     *num_config = n;
     return EGL_TRUE;
@@ -834,7 +851,7 @@
 
     
     // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, 
-    // to do  this, we have to go through the attrib_list array once
+    // to do this, we have to go through the attrib_list array once
     // to figure out both its size and if it contains an EGL_CONFIG_ID
     // key. If so, the full array is copied and patched.
     // NOTE: we assume that there can be only one occurrence
@@ -858,16 +875,20 @@
         memcpy(new_list, attrib_list, size*sizeof(EGLint));
 
         // patch the requested EGL_CONFIG_ID
-        int i, index;
+        bool found = false;
+        EGLConfig ourConfig(0);
         EGLint& configId(new_list[patch_index+1]);
-        uniqueIdToConfig(dp, configId, i, index);
-        
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            cnx->egl.eglGetConfigAttrib(
-                    dp->disp[i].dpy, dp->disp[i].config[index], 
-                    EGL_CONFIG_ID, &configId);
+        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
+            if (dp->configs[i].configId == configId) {
+                ourConfig = EGLConfig(i);
+                configId = dp->configs[i].implConfigId;
+                found = true;
+                break;
+            }
+        }
 
+        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
+        if (found && cnx->dso) {
             // and switch to the new list
             attrib_list = const_cast<const EGLint *>(new_list);
 
@@ -880,12 +901,13 @@
             // which one.
 
             res = cnx->egl.eglChooseConfig(
-                    dp->disp[i].dpy, attrib_list, configs, config_size, &n);
+                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
+                    attrib_list, configs, config_size, &n);
             if (res && n>0) {
                 // n has to be 0 or 1, by construction, and we already know
                 // which config it will return (since there can be only one).
                 if (configs) {
-                    configs[0] = MAKE_CONFIG(i, index);
+                    configs[0] = ourConfig;
                 }
                 *num_config = 1;
             }
@@ -895,6 +917,7 @@
         return res;
     }
 
+
     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
@@ -902,15 +925,14 @@
                     dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
                 if (configs) {
                     // now we need to convert these client EGLConfig to our
-                    // internal EGLConfig format. This is done in O(n log n).
+                    // internal EGLConfig format.
+                    // This is done in O(n Log(n)) time.
                     for (int j=0 ; j<n ; j++) {
-                        int index = binarySearch<EGLConfig>(
-                                dp->disp[i].config, 0,
-                                dp->disp[i].numConfigs-1, configs[j]);
+                        egl_config_t key(i, configs[j]);
+                        intptr_t index = binarySearch<egl_config_t>(
+                                dp->configs, 0, dp->numTotalConfigs, key);
                         if (index >= 0) {
-                            if (configs) {
-                                configs[j] = MAKE_CONFIG(i, index);
-                            }
+                            configs[j] = EGLConfig(index);
                         } else {
                             return setError(EGL_BAD_CONFIG, EGL_FALSE);
                         }
@@ -930,18 +952,16 @@
         EGLint attribute, EGLint *value)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (!cnx) return EGL_FALSE;
     
     if (attribute == EGL_CONFIG_ID) {
-        // EGL_CONFIG_IDs must be unique, just use the order of the selected
-        // EGLConfig.
-        *value = configToUniqueId(dp, i, index);
+        *value = dp->configs[intptr_t(config)].configId;
         return EGL_TRUE;
     }
     return cnx->egl.eglGetConfigAttrib(
-            dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
+            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+            dp->configs[intptr_t(config)].config, attribute, value);
 }
 
 // ----------------------------------------------------------------------------
@@ -953,13 +973,14 @@
                                     const EGLint *attrib_list)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         EGLSurface surface = cnx->egl.eglCreateWindowSurface(
-                dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);       
+                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+                dp->configs[intptr_t(config)].config, window, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
+                    dp->configs[intptr_t(config)].impl, cnx);
             return s;
         }
     }
@@ -971,13 +992,14 @@
                                     const EGLint *attrib_list)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
-                dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
+                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
+                    dp->configs[intptr_t(config)].impl, cnx);
             return s;
         }
     }
@@ -988,13 +1010,14 @@
                                     const EGLint *attrib_list)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
-                dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
+                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+                dp->configs[intptr_t(config)].config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
+                    dp->configs[intptr_t(config)].impl, cnx);
             return s;
         }
     }
@@ -1030,27 +1053,35 @@
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
 
-    return s->cnx->egl.eglQuerySurface(
-            dp->disp[s->impl].dpy, s->surface, attribute, value);
+    EGLBoolean result(EGL_TRUE);
+    if (attribute == EGL_CONFIG_ID) {
+        // We need to remap EGL_CONFIG_IDs
+        *value = dp->configs[intptr_t(s->config)].configId;
+    } else {
+        result = s->cnx->egl.eglQuerySurface(
+                dp->disp[s->impl].dpy, s->surface, attribute, value);
+    }
+
+    return result;
 }
 
 // ----------------------------------------------------------------------------
-// contextes
+// Contexts
 // ----------------------------------------------------------------------------
 
 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
                             EGLContext share_list, const EGLint *attrib_list)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         if (share_list != EGL_NO_CONTEXT) {
             egl_context_t* const c = get_context(share_list);
             share_list = c->context;
         }
         EGLContext context = cnx->egl.eglCreateContext(
-                dp->disp[i].dpy, dp->disp[i].config[index],
+                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+                dp->configs[intptr_t(config)].config,
                 share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
             // figure out if it's a GLESv1 or GLESv2
@@ -1068,7 +1099,8 @@
                     }
                 };
             }
-            egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
+            egl_context_t* c = new egl_context_t(dpy, context, config,
+                    dp->configs[intptr_t(config)].impl, cnx, version);
             return c;
         }
     }
@@ -1213,8 +1245,16 @@
     egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
 
-    return c->cnx->egl.eglQueryContext(
-            dp->disp[c->impl].dpy, c->context, attribute, value);
+    EGLBoolean result(EGL_TRUE);
+    if (attribute == EGL_CONFIG_ID) {
+        *value = dp->configs[intptr_t(c->config)].configId;
+    } else {
+        // We need to remap EGL_CONFIG_IDs
+        result = c->cnx->egl.eglQueryContext(
+                dp->disp[c->impl].dpy, c->context, attribute, value);
+    }
+
+    return result;
 }
 
 EGLContext eglGetCurrentContext(void)
@@ -1586,13 +1626,13 @@
           EGLConfig config, const EGLint *attrib_list)
 {
     egl_display_t const* dp = 0;
-    int i=0, index=0;
-    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
+    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (!cnx) return EGL_FALSE;
     if (cnx->egl.eglCreatePbufferFromClientBuffer) {
         return cnx->egl.eglCreatePbufferFromClientBuffer(
-                dp->disp[i].dpy, buftype, buffer, 
-                dp->disp[i].config[index], attrib_list);
+                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+                buftype, buffer,
+                dp->configs[intptr_t(config)].config, attrib_list);
     }
     return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 6eaf0cc..f1c6532 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -125,8 +125,6 @@
             metrics.setToDefaults();
             PackageParser.PackageLite pkg = packageParser.parsePackageLite(
                     archiveFilePath, 0);
-            ret.packageName = pkg.packageName;
-            ret.installLocation = pkg.installLocation;
             // Nuke the parser reference right away and force a gc
             packageParser = null;
             Runtime.getRuntime().gc();
@@ -136,6 +134,7 @@
                 return ret;
             }
             ret.packageName = pkg.packageName;
+            ret.installLocation = pkg.installLocation;
             ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags);
             return ret;
         }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 75045d7..0fccbe7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -7,6 +7,7 @@
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
 
     <application
+        android:persistent="true"
         android:allowClearUserData="false"
         android:label="@string/app_label"
         android:icon="@drawable/ic_launcher_settings">
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c786f94..3b3904a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index b0b2d7a..77ccf41 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b29c6e6..ff4ff74 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5019,7 +5019,12 @@
 
         @Override
         void handleReturnCode() {
-            processPendingInstall(mArgs, mRet);
+            // If mArgs is null, then MCS couldn't be reached. When it
+            // reconnects, it will try again to install. At that point, this
+            // will succeed.
+            if (mArgs != null) {
+                processPendingInstall(mArgs, mRet);
+            }
         }
 
         @Override
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 5615232..4940311 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5514,7 +5514,7 @@
                 throw new SecurityException(
                         "Injecting to another application requires INJECT_EVENTS permission");
             case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
-                Slog.v(TAG, "Input event injection succeeded.");
+                //Slog.v(TAG, "Input event injection succeeded.");
                 return true;
             case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
                 Slog.w(TAG, "Input event injection timed out.");
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bcbda3e..162fffe 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6101,17 +6101,19 @@
     }
 
     public void handleApplicationStrictModeViolation(
-        IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) {
+            IBinder app,
+            int violationMask,
+            StrictMode.ViolationInfo info) {
         ProcessRecord r = findAppProcess(app);
 
         if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
-            Integer stackFingerprint = crashInfo.stackTrace.hashCode();
+            Integer stackFingerprint = info.crashInfo.stackTrace.hashCode();
             boolean logIt = true;
             synchronized (mAlreadyLoggedViolatedStacks) {
                 if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) {
                     logIt = false;
                     // TODO: sub-sample into EventLog for these, with
-                    // the crashInfo.durationMillis?  Then we'd get
+                    // the info.durationMillis?  Then we'd get
                     // the relative pain numbers, without logging all
                     // the stack traces repeatedly.  We'd want to do
                     // likewise in the client code, which also does
@@ -6124,7 +6126,7 @@
                 }
             }
             if (logIt) {
-                logStrictModeViolationToDropBox(r, crashInfo);
+                logStrictModeViolationToDropBox(r, info);
             }
         }
 
@@ -6139,7 +6141,7 @@
                 data.put("result", result);
                 data.put("app", r);
                 data.put("violationMask", violationMask);
-                data.put("crashInfo", crashInfo);
+                data.put("info", info);
                 msg.obj = data;
                 mHandler.sendMessage(msg);
 
@@ -6154,9 +6156,10 @@
     // these in quick succession so we try to batch these together to
     // minimize disk writes, number of dropbox entries, and maximize
     // compression, by having more fewer, larger records.
-    private void logStrictModeViolationToDropBox(ProcessRecord process,
-                                                 ApplicationErrorReport.CrashInfo crashInfo) {
-        if (crashInfo == null) {
+    private void logStrictModeViolationToDropBox(
+            ProcessRecord process,
+            StrictMode.ViolationInfo info) {
+        if (info == null) {
             return;
         }
         final boolean isSystemApp = process == null ||
@@ -6177,12 +6180,16 @@
             appendDropBoxProcessHeaders(process, sb);
             sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
             sb.append("System-App: ").append(isSystemApp).append("\n");
-            if (crashInfo != null && crashInfo.durationMillis != -1) {
-                sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n");
+            sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n");
+            if (info.violationNumThisLoop != 0) {
+                sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n");
+            }
+            if (info != null && info.durationMillis != -1) {
+                sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
             }
             sb.append("\n");
-            if (crashInfo != null && crashInfo.stackTrace != null) {
-                sb.append(crashInfo.stackTrace);
+            if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
+                sb.append(info.crashInfo.stackTrace);
             }
             sb.append("\n");
 
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index a60d2be..03194ff 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -135,9 +135,9 @@
         }
 
         // TODO: We don't check for SecurityException here (requires
-        // READ_PHONE_STATE permission).
+        // CALL_PRIVILEGED permission).
         if (scheme.equals("voicemail")) {
-            return TelephonyManager.getDefault().getVoiceMailNumber();
+            return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
         }
 
         if (context == null) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ab63017..aa916e0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -665,6 +665,25 @@
     }
 
     /**
+     * Returns the complete voice mail number. Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+     *
+     * @hide
+     */
+    public String getCompleteVoiceMailNumber() {
+        try {
+            return getSubscriberInfo().getCompleteVoiceMailNumber();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
      * Returns the voice mail count. Return 0 if unavailable.
      * <p>
      * Requires Permission:
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
new file mode 100644
index 0000000..9822694
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) 2010 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 com.android.internal.telephony;
+
+
+
+import android.content.Context;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RegistrantList;
+import android.telephony.PhoneStateListener;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ *
+ * CallManager class provides an abstract layer for PhoneApp to access
+ * and control calls. It implements Phone interface.
+ *
+ * CallManager provides call and connection control as well as
+ * channel capability.
+ *
+ * There are three categories of APIs CallManager provided
+ *
+ *  1. Call control and operation, such as dial() and hangup()
+ *  2. Channel capabilities, such as CanConference()
+ *  3. Register notification
+ *
+ *
+ */
+public final class CallManager {
+
+    private static final int EVENT_DISCONNECT = 100;
+    private static final int EVENT_CALL_STATE_CHANGED = 101;
+
+
+    // Singleton instance
+    private static final CallManager INSTANCE = new CallManager();
+
+    // list of registered phones
+    private final ArrayList<Phone> mPhones;
+
+    // list of supported ringing calls
+    private final ArrayList<Call> mRingingCalls;
+
+    // list of supported background calls
+    private final ArrayList<Call> mBackgroundCalls;
+
+    // list of supported foreground calls
+    private final ArrayList<Call> mForegroundCalls;
+
+    // empty connection list
+    private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
+
+    // default phone as the first phone registered
+    private Phone mDefaultPhone;
+
+    // state registrants
+    protected final RegistrantList mPreciseCallStateRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mNewRingingConnectionRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mIncomingRingRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mDisconnectRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mServiceStateRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mMmiCompleteRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mMmiRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mUnknownConnectionRegistrants
+    = new RegistrantList();
+
+    protected final RegistrantList mSuppServiceFailedRegistrants
+    = new RegistrantList();
+
+    private CallManager() {
+        mPhones = new ArrayList<Phone>();
+        mRingingCalls = new ArrayList<Call>();
+        mBackgroundCalls = new ArrayList<Call>();
+        mForegroundCalls = new ArrayList<Call>();
+        mDefaultPhone = null;
+    }
+
+    /**
+     * get singleton instance of CallManager
+     * @return CallManager
+     */
+    public static CallManager getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Register phone to CallManager
+     * @param phone
+     * @return
+     */
+    public boolean registerPhone(Phone phone) {
+        if (phone != null && !mPhones.contains(phone)) {
+            if (mPhones.isEmpty()) {
+                mDefaultPhone = phone;
+            }
+            mPhones.add(phone);
+            mRingingCalls.add(phone.getRingingCall());
+            mBackgroundCalls.add(phone.getBackgroundCall());
+            mForegroundCalls.add(phone.getForegroundCall());
+            registerForPhoneStates(phone);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * unregister phone from CallManager
+     * @param phone
+     */
+    public void unregisterPhone(Phone phone) {
+        if (phone != null && !mPhones.contains(phone)) {
+            mPhones.remove(phone);
+            mRingingCalls.remove(phone.getRingingCall());
+            mBackgroundCalls.remove(phone.getBackgroundCall());
+            mForegroundCalls.remove(phone.getForegroundCall());
+            unregisterForPhoneStates(phone);
+            if (phone == mDefaultPhone) {
+                if (mPhones.isEmpty()) {
+                    mDefaultPhone = null;
+                } else {
+                    mDefaultPhone = mPhones.get(0);
+                }
+            }
+        }
+    }
+
+    private void registerForPhoneStates(Phone phone) {
+        phone.registerForPreciseCallStateChanged(mHandler, EVENT_CALL_STATE_CHANGED, null);
+        phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
+    }
+
+    private void unregisterForPhoneStates(Phone phone) {
+        phone.unregisterForPreciseCallStateChanged(mHandler);
+        phone.unregisterForDisconnect(mHandler);
+    }
+
+    /**
+     * Answers a ringing or waiting call.
+     *
+     * Active call, if any, go on hold.
+     * If active call can't be held, i.e., a background call of the same channel exists,
+     * the active call will be hang up.
+     *
+     * Answering occurs asynchronously, and final notification occurs via
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}.
+     *
+     * @exception CallStateException when call is not ringing or waiting
+     */
+    public void acceptCall(Call ringingCall) throws CallStateException {
+        Phone ringingPhone = ringingCall.getPhone();
+
+        if ( hasActiveFgCall() ) {
+            Phone activePhone = getActiveFgCall().getPhone();
+            boolean hasBgCall = activePhone.getBackgroundCall().isIdle();
+            boolean sameChannel = (activePhone == ringingPhone);
+
+            if (sameChannel && hasBgCall) {
+                getActiveFgCall().hangup();
+            } else if (!sameChannel && !hasBgCall) {
+                activePhone.switchHoldingAndActive();
+            } else if (!sameChannel && hasBgCall) {
+                getActiveFgCall().hangup();
+            }
+        }
+
+        ringingPhone.acceptCall();
+    }
+
+    /**
+     * Reject (ignore) a ringing call. In GSM, this means UDUB
+     * (User Determined User Busy). Reject occurs asynchronously,
+     * and final notification occurs via
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}.
+     *
+     * @exception CallStateException when no call is ringing or waiting
+     */
+    public void rejectCall(Call ringingCall) throws CallStateException {
+        Phone ringingPhone = ringingCall.getPhone();
+
+        ringingPhone.rejectCall();
+    }
+
+    /**
+     * Places any active calls on hold, and makes any held calls
+     *  active. Switch occurs asynchronously and may fail.
+     * Final notification occurs via
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}.
+     *
+     * @exception CallStateException if active call is ringing, waiting, or
+     * dialing/alerting, or heldCall can�t be active.
+     * In these cases, this operation may not be performed.
+     */
+    public void switchHoldingAndActive(Call heldCall) throws CallStateException {
+        Phone activePhone = null;
+        Phone heldPhone = null;
+
+        if (hasActiveFgCall()) {
+            activePhone = getActiveFgCall().getPhone();
+        }
+
+        if (heldCall != null) {
+            heldPhone = heldCall.getPhone();
+        }
+
+        if (activePhone != heldPhone) {
+            activePhone.switchHoldingAndActive();
+        }
+
+        heldPhone.switchHoldingAndActive();
+    }
+
+    /**
+     * Whether or not the phone can conference in the current phone
+     * state--that is, one call holding and one call active.
+     * @return true if the phone can conference; false otherwise.
+     */
+    public boolean canConference(Call heldCall) {
+        Phone activePhone = null;
+        Phone heldPhone = null;
+
+        if (hasActiveFgCall()) {
+            activePhone = getActiveFgCall().getPhone();
+        }
+
+        if (heldCall != null) {
+            heldPhone = heldCall.getPhone();
+        }
+
+        return (heldPhone == activePhone);
+    }
+
+    /**
+     * Conferences holding and active. Conference occurs asynchronously
+     * and may fail. Final notification occurs via
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}.
+     *
+     * @exception CallStateException if canConference() would return false.
+     * In these cases, this operation may not be performed.
+     */
+    public void conference(Call heldCall) throws CallStateException {
+        if (canConference(heldCall))
+            throw(new CallStateException("Can't conference foreground and selected background call"));
+
+        heldCall.getPhone().conference();
+    }
+
+    /**
+     * Initiate a new voice connection. This happens asynchronously, so you
+     * cannot assume the audio path is connected (or a call index has been
+     * assigned) until PhoneStateChanged notification has occurred.
+     *
+     * @exception CallStateException if a new outgoing call is not currently
+     * possible because no more call slots exist or a call exists that is
+     * dialing, alerting, ringing, or waiting.  Other errors are
+     * handled asynchronously.
+     */
+    public Connection dial(Phone phone, String dialString) throws CallStateException {
+        return phone.dial(dialString);
+    }
+
+    /**
+     * Initiate a new voice connection. This happens asynchronously, so you
+     * cannot assume the audio path is connected (or a call index has been
+     * assigned) until PhoneStateChanged notification has occurred.
+     *
+     * @exception CallStateException if a new outgoing call is not currently
+     * possible because no more call slots exist or a call exists that is
+     * dialing, alerting, ringing, or waiting.  Other errors are
+     * handled asynchronously.
+     */
+    public Connection dial(Phone phone, String dialString, UUSInfo uusInfo) throws CallStateException {
+        return phone.dial(dialString, uusInfo);
+    }
+
+    /**
+     * clear disconnect connection for each phone
+     */
+    public void clearDisconnected() {
+        for(Phone phone : mPhones) {
+            phone.clearDisconnected();
+        }
+    }
+
+    /**
+     * Whether or not the phone can do explicit call transfer in the current
+     * phone state--that is, one call holding and one call active.
+     * @return true if the phone can do explicit call transfer; false otherwise.
+     */
+    public boolean canTransfer(Call heldCall) {
+        Phone activePhone = null;
+        Phone heldPhone = null;
+
+        if (hasActiveFgCall()) {
+            activePhone = getActiveFgCall().getPhone();
+        }
+
+        if (heldCall != null) {
+            heldPhone = heldCall.getPhone();
+        }
+
+        return (heldPhone == activePhone && activePhone.canTransfer());
+    }
+
+    /**
+     * Connects the held call and active call
+     * Disconnects the subscriber from both calls
+     *
+     * Explicit Call Transfer occurs asynchronously
+     * and may fail. Final notification occurs via
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}.
+     *
+     * @exception CallStateException if canTransfer() would return false.
+     * In these cases, this operation may not be performed.
+     */
+    public void explicitCallTransfer(Call heldCall) throws CallStateException {
+        if (canTransfer(heldCall)) {
+            heldCall.getPhone().explicitCallTransfer();
+        }
+    }
+
+    /**
+     * Returns a list of MMI codes that are pending for a phone. (They have initiated
+     * but have not yet completed).
+     * Presently there is only ever one.
+     *
+     * Use <code>registerForMmiInitiate</code>
+     * and <code>registerForMmiComplete</code> for change notification.
+     * @return null if phone doesn't have or support mmi code
+     */
+    public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
+        return null;
+    }
+
+    /**
+     * Sends user response to a USSD REQUEST message.  An MmiCode instance
+     * representing this response is sent to handlers registered with
+     * registerForMmiInitiate.
+     *
+     * @param ussdMessge    Message to send in the response.
+     * @return false if phone doesn't support ussd service
+     */
+    public boolean sendUssdResponse(Phone phone, String ussdMessge) {
+        return false;
+    }
+
+    /**
+     * Mutes or unmutes the microphone for the active call. The microphone
+     * is automatically unmuted if a call is answered, dialed, or resumed
+     * from a holding state.
+     *
+     * @param muted true to mute the microphone,
+     * false to activate the microphone.
+     */
+
+    public void setMute(boolean muted) {
+        if (hasActiveFgCall()) {
+            getActiveFgCall().getPhone().setMute(muted);
+        }
+    }
+
+    /**
+     * Gets current mute status. Use
+     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+     * java.lang.Object) registerForPreciseCallStateChanged()}
+     * as a change notifcation, although presently phone state changed is not
+     * fired when setMute() is called.
+     *
+     * @return true is muting, false is unmuting
+     */
+    public boolean getMute() {
+        if (hasActiveFgCall()) {
+            return getActiveFgCall().getPhone().getMute();
+        }
+        return false;
+    }
+
+    /**
+     * Play a DTMF tone on the active call.
+     *
+     * @param c should be one of 0-9, '*' or '#'. Other values will be
+     * silently ignored.
+     * @return false if no active call or the active call doesn't support
+     *         dtmf tone
+     */
+    public boolean sendDtmf(char c) {
+        if (hasActiveFgCall()) {
+            getActiveFgCall().getPhone().sendDtmf(c);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Start to paly a DTMF tone on the active call.
+     * or there is a playing DTMF tone.
+     * @param c should be one of 0-9, '*' or '#'. Other values will be
+     * silently ignored.
+     *
+     * @return false if no active call or the active call doesn't support
+     *         dtmf tone
+     */
+    public boolean startDtmf(char c) {
+        if (hasActiveFgCall()) {
+            getActiveFgCall().getPhone().sendDtmf(c);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Stop the playing DTMF tone. Ignored if there is no playing DTMF
+     * tone or no active call.
+     */
+    public void stopDtmf(Phone phone) {
+        phone.stopDtmf();
+    }
+
+    /**
+     * send burst DTMF tone, it can send the string as single character or multiple character
+     * ignore if there is no active call or not valid digits string.
+     * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
+     * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
+     * this api can send single character and multiple character, also, this api has response
+     * back to caller.
+     *
+     * @param dtmfString is string representing the dialing digit(s) in the active call
+     * @param on the DTMF ON length in milliseconds, or 0 for default
+     * @param off the DTMF OFF length in milliseconds, or 0 for default
+     * @param onComplete is the callback message when the action is processed by BP
+     *
+     */
+    public boolean sendBurstDtmf(Phone phone, String dtmfString, int on, int off, Message onComplete) {
+        if (hasActiveFgCall()) {
+            getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Notifies when a voice connection has disconnected, either due to local
+     * or remote hangup or error.
+     *
+     *  Messages received from this will have the following members:<p>
+     *  <ul><li>Message.obj will be an AsyncResult</li>
+     *  <li>AsyncResult.userObj = obj</li>
+     *  <li>AsyncResult.result = a Connection object that is
+     *  no longer connected.</li></ul>
+     */
+    public void registerForDisconnect(Handler h, int what, Object obj) {
+        mDisconnectRegistrants.addUnique(h, what, obj);
+    }
+
+    /**
+     * Unregisters for voice disconnection notification.
+     * Extraneous calls are tolerated silently
+     */
+    public void unregisterForDisconnect(Handler h){
+        mDisconnectRegistrants.remove(h);
+    }
+
+    /**
+     * Register for getting notifications for change in the Call State {@link Call.State}
+     * This is called PreciseCallState because the call state is more precise than the
+     * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
+     *
+     * Resulting events will have an AsyncResult in <code>Message.obj</code>.
+     * AsyncResult.userData will be set to the obj argument here.
+     * The <em>h</em> parameter is held only by a weak reference.
+     */
+    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
+        mPreciseCallStateRegistrants.addUnique(h, what, obj);
+    }
+
+    /**
+     * Unregisters for voice call state change notifications.
+     * Extraneous calls are tolerated silently.
+     */
+    public void unregisterForPreciseCallStateChanged(Handler h){
+        mPreciseCallStateRegistrants.remove(h);
+    }
+
+    /**
+     * Notifies when a previously untracked non-ringing/waiting connection has appeared.
+     * This is likely due to some other entity (eg, SIM card application) initiating a call.
+     */
+    public void registerForUnknownConnection(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for unknown connection notifications.
+     */
+    public void unregisterForUnknownConnection(Handler h){}
+
+
+    /**
+     * Notifies when a new ringing or waiting connection has appeared.<p>
+     *
+     *  Messages received from this:
+     *  Message.obj will be an AsyncResult
+     *  AsyncResult.userObj = obj
+     *  AsyncResult.result = a Connection. <p>
+     *  Please check Connection.isRinging() to make sure the Connection
+     *  has not dropped since this message was posted.
+     *  If Connection.isRinging() is true, then
+     *   Connection.getCall() == Phone.getRingingCall()
+     */
+    public void registerForNewRingingConnection(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for new ringing connection notification.
+     * Extraneous calls are tolerated silently
+     */
+
+    public void unregisterForNewRingingConnection(Handler h){}
+
+    /**
+     * Notifies when an incoming call rings.<p>
+     *
+     *  Messages received from this:
+     *  Message.obj will be an AsyncResult
+     *  AsyncResult.userObj = obj
+     *  AsyncResult.result = a Connection. <p>
+     */
+    public void registerForIncomingRing(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for ring notification.
+     * Extraneous calls are tolerated silently
+     */
+
+    public void unregisterForIncomingRing(Handler h){}
+
+    /**
+     * Notifies when out-band ringback tone is needed.<p>
+     *
+     *  Messages received from this:
+     *  Message.obj will be an AsyncResult
+     *  AsyncResult.userObj = obj
+     *  AsyncResult.result = boolean, true to start play ringback tone
+     *                       and false to stop. <p>
+     */
+    public void registerForRingbackTone(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for ringback tone notification.
+     */
+
+    public void unregisterForRingbackTone(Handler h){}
+
+    /**
+     * Registers the handler to reset the uplink mute state to get
+     * uplink audio.
+     */
+    public void registerForResendIncallMute(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for resend incall mute notifications.
+     */
+    public void unregisterForResendIncallMute(Handler h){}
+
+
+
+    /**
+     * Register for notifications of initiation of a new MMI code request.
+     * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
+     *
+     * Example: If Phone.dial is called with "*#31#", then the app will
+     * be notified here.<p>
+     *
+     * The returned <code>Message.obj</code> will contain an AsyncResult.
+     *
+     * <code>obj.result</code> will be an "MmiCode" object.
+     */
+    public void registerForMmiInitiate(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for new MMI initiate notification.
+     * Extraneous calls are tolerated silently
+     */
+    public void unregisterForMmiInitiate(Handler h){}
+
+    /**
+     * Register for notifications that an MMI request has completed
+     * its network activity and is in its final state. This may mean a state
+     * of COMPLETE, FAILED, or CANCELLED.
+     *
+     * <code>Message.obj</code> will contain an AsyncResult.
+     * <code>obj.result</code> will be an "MmiCode" object
+     */
+    public void registerForMmiComplete(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for MMI complete notification.
+     * Extraneous calls are tolerated silently
+     */
+    public void unregisterForMmiComplete(Handler h){}
+
+    /**
+     * Registration point for Ecm timer reset
+     * @param h handler to notify
+     * @param what user-defined message code
+     * @param obj placed in Message.obj
+     */
+    public void registerForEcmTimerReset(Handler h, int what, Object obj){}
+
+    /**
+     * Unregister for notification for Ecm timer reset
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForEcmTimerReset(Handler h){}
+
+
+
+    /**
+     * Register for ServiceState changed.
+     * Message.obj will contain an AsyncResult.
+     * AsyncResult.result will be a ServiceState instance
+     */
+    public void registerForServiceStateChanged(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for ServiceStateChange notification.
+     * Extraneous calls are tolerated silently
+     */
+    public void unregisterForServiceStateChanged(Handler h){}
+
+    /**
+     * Register for Supplementary Service notifications from the network.
+     * Message.obj will contain an AsyncResult.
+     * AsyncResult.result will be a SuppServiceNotification instance.
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForSuppServiceNotification(Handler h, int what, Object obj){}
+
+    /**
+     * Unregisters for Supplementary Service notifications.
+     * Extraneous calls are tolerated silently
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForSuppServiceNotification(Handler h){}
+
+    /**
+     * Register for notifications when a supplementary service attempt fails.
+     * Message.obj will contain an AsyncResult.
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForSuppServiceFailed(Handler h, int what, Object obj){}
+
+    /**
+     * Unregister for notifications when a supplementary service attempt fails.
+     * Extraneous calls are tolerated silently
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForSuppServiceFailed(Handler h){}
+
+    /**
+     * Register for notifications when a sInCall VoicePrivacy is enabled
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){}
+
+    /**
+     * Unegister for notifications when a sInCall VoicePrivacy is enabled
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForInCallVoicePrivacyOn(Handler h){}
+
+    /**
+     * Register for notifications when a sInCall VoicePrivacy is disabled
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){}
+
+    /**
+     * Unegister for notifications when a sInCall VoicePrivacy is disabled
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForInCallVoicePrivacyOff(Handler h){}
+
+    /**
+     * Register for notifications when CDMA OTA Provision status change
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){}
+
+    /**
+     * Unegister for notifications when CDMA OTA Provision status change
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForCdmaOtaStatusChange(Handler h){}
+
+    /**
+     * Registration point for subscription info ready
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){}
+
+    /**
+     * Unregister for notifications for subscription info
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForSubscriptionInfoReady(Handler h){}
+
+    /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
+     * 1. APIs to access list of calls
+     * 2. APIs to check if any active call, which has connection other than
+     * disconnected ones, pleaser refer to Call.isIdle()
+     * 3. APIs to return first active call
+     * 4. APIs to return the connections of first active call
+     * 5. APIs to return other property of first active call
+     */
+
+    /**
+     * @return list of ringing calls
+     */
+    public ArrayList<Call> getRingingCalls() {
+        return mBackgroundCalls;
+    }
+
+    /**
+     * @return list of background calls
+     */
+    public ArrayList<Call> getBackgroundCalls() {
+        return mBackgroundCalls;
+    }
+
+    /**
+     * Return true if there is at least one active foreground call
+     */
+    public boolean hasActiveFgCall() {
+        return (getFirstActiveCall(mForegroundCalls) != null);
+    }
+
+    /**
+     * Return true if there is at least one active background call
+     */
+    public boolean hasActiveBgCall() {
+        // TODO since hasActiveBgCall may get called often
+        // better to cache it to improve performance
+        return (getFirstActiveCall(mBackgroundCalls) != null);
+    }
+
+    /**
+     * Return true if there is at least one active ringing call
+     *
+     */
+    public boolean hasActiveRingingCall() {
+        return (getFirstActiveCall(mRingingCalls) != null);
+    }
+
+    /**
+     * return the active foreground call from foreground calls
+     *
+     * Active call means the call is NOT in Call.State.IDLE
+     *
+     * 1. If there is active foreground call, return it
+     * 2. If there is no active foreground call, return the
+     *    foreground call associated with default phone, which state is IDLE.
+     * 3. If there is no phone registered at all, return null.
+     *
+     */
+    public Call getActiveFgCall() {
+        for (Call call : mForegroundCalls) {
+            if (call.getState() != Call.State.IDLE) {
+                return call;
+            }
+        }
+        return (mDefaultPhone == null) ?
+                null : mDefaultPhone.getForegroundCall();
+    }
+
+    /**
+     * return one active background call from background calls
+     *
+     * Active call means the call is NOT idle defined by Call.isIdle()
+     *
+     * 1. If there is only one active background call, return it
+     * 2. If there is more than one active background call, return the first one
+     * 3. If there is no active background call, return the background call
+     *    associated with default phone, which state is IDLE.
+     * 4. If there is no background call at all, return null.
+     *
+     * Complete background calls list can be get by getBackgroundCalls()
+     */
+    public Call getFirstActiveBgCall() {
+        for (Call call : mBackgroundCalls) {
+            if (!call.isIdle()) {
+                return call;
+            }
+        }
+        return (mDefaultPhone == null) ?
+                null : mDefaultPhone.getBackgroundCall();
+    }
+
+    /**
+     * return one active ringing call from ringing calls
+     *
+     * Active call means the call is NOT idle defined by Call.isIdle()
+     *
+     * 1. If there is only one active ringing call, return it
+     * 2. If there is more than one active ringing call, return the first one
+     * 3. If there is no active ringing call, return the ringing call
+     *    associated with default phone, which state is IDLE.
+     * 4. If there is no ringing call at all, return null.
+     *
+     * Complete ringing calls list can be get by getRingingCalls()
+     */
+    public Call getFirstActiveRingingCall() {
+        for (Call call : mRingingCalls) {
+            if (!call.isIdle()) {
+                return call;
+            }
+        }
+        return (mDefaultPhone == null) ?
+                null : mDefaultPhone.getRingingCall();
+    }
+
+    /**
+     * @return the state of active foreground call
+     * return IDLE if there is no active foreground call
+     */
+    public Call.State getActiveFgCallState() {
+        Call fgCall = getActiveFgCall();
+
+        if (fgCall != null) {
+            return fgCall.getState();
+        }
+
+        return Call.State.IDLE;
+    }
+
+    /**
+     * @return the connections of active foreground call
+     * return null if there is no active foreground call
+     */
+    public List<Connection> getFgCallConnections() {
+        Call fgCall = getActiveFgCall();
+        if ( fgCall != null) {
+            return fgCall.getConnections();
+        }
+        return emptyConnections;
+    }
+
+    /**
+     * @return the connections of active background call
+     * return empty list if there is no active background call
+     */
+    public List<Connection> getBgCallConnections() {
+        Call bgCall = getActiveFgCall();
+        if ( bgCall != null) {
+            return bgCall.getConnections();
+        }
+        return emptyConnections;
+    }
+
+    /**
+     * @return the latest connection of active foreground call
+     * return null if there is no active foreground call
+     */
+    public Connection getFgCallLatestConnection() {
+        Call fgCall = getActiveFgCall();
+        if ( fgCall != null) {
+            return fgCall.getLatestConnection();
+        }
+        return null;
+    }
+
+    /**
+     * @return true if there is at least one Foreground call in disconnected state
+     */
+    public boolean hasDisconnectedFgCall() {
+        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
+    }
+
+    /**
+     * @return true if there is at least one background call in disconnected state
+     */
+    public boolean hasDisconnectedBgCall() {
+        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
+    }
+
+    /**
+     * @return the first active call from a call list
+     */
+    private  Call getFirstActiveCall(ArrayList<Call> calls) {
+        for (Call call : calls) {
+            if (!call.isIdle()) {
+                return call;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return the first call in a the Call.state from a call list
+     */
+    private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
+        for (Call call : calls) {
+            if (call.getState() == state) {
+                return call;
+            }
+        }
+        return null;
+    }
+
+
+
+
+    private Handler mHandler = new Handler() {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_DISCONNECT:
+                    mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    break;
+                case EVENT_CALL_STATE_CHANGED:
+                    mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    break;
+            }
+        }
+    };
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index e74b9e4..5cba2e1 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -59,6 +59,11 @@
     String getVoiceMailNumber();
 
     /**
+     * Retrieves the complete voice mail number.
+     */
+    String getCompleteVoiceMailNumber();
+
+    /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     String getVoiceMailAlphaTag();
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index 4f71bb1..86c86bb 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.telephony.PhoneNumberUtils;
 import android.util.Log;
 
 public class PhoneSubInfo extends IPhoneSubInfo.Stub {
@@ -29,6 +30,9 @@
     private Context mContext;
     private static final String READ_PHONE_STATE =
         android.Manifest.permission.READ_PHONE_STATE;
+    private static final String CALL_PRIVILEGED =
+        // TODO Add core/res/AndriodManifest.xml#READ_PRIVILEGED_PHONE_STATE
+        android.Manifest.permission.CALL_PRIVILEGED;
 
     public PhoneSubInfo(Phone phone) {
         mPhone = phone;
@@ -101,7 +105,22 @@
      */
     public String getVoiceMailNumber() {
         mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
-        return (String) mPhone.getVoiceMailNumber();
+        String number = PhoneNumberUtils.extractNetworkPortion(mPhone.getVoiceMailNumber());
+        Log.d(LOG_TAG, "VM: PhoneSubInfo.getVoiceMailNUmber: "); // + number);
+        return number;
+    }
+
+    /**
+     * Retrieves the compelete voice mail number.
+     *
+     * @hide
+     */
+    public String getCompleteVoiceMailNumber() {
+        mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED,
+                "Requires CALL_PRIVILEGED");
+        String number = mPhone.getVoiceMailNumber();
+        Log.d(LOG_TAG, "VM: PhoneSubInfo.getCompleteVoiceMailNUmber: "); // + number);
+        return number;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
index 202ded2..7009893 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
@@ -82,6 +82,13 @@
     }
 
     /**
+     * Retrieves the complete voice mail number.
+     */
+    public String getCompleteVoiceMailNumber() {
+        return mPhoneSubInfo.getCompleteVoiceMailNumber();
+    }
+
+    /**
      * Retrieves the alpha identifier associated with the voice mail number.
      */
     public String getVoiceMailAlphaTag() {