Merge "SIP: add PEER_NOT_REACHABLE error feedback." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index d1dfc09..8e8a671 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -152023,6 +152023,17 @@
  visibility="public"
 >
 </method>
+<method name="getPsc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="setLacAndCid"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f8407c2..d8b5253 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3107,18 +3107,11 @@
         /**
          * For system applications on userdebug/eng builds, log stack
          * traces of disk and network access to dropbox for analysis.
-         *
-         * Similar logic exists in SystemServer.java.
          */
         if ((data.appInfo.flags &
              (ApplicationInfo.FLAG_SYSTEM |
-              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0 &&
-            !"user".equals(Build.TYPE)) {
-            StrictMode.setThreadPolicy(
-                StrictMode.DISALLOW_DISK_WRITE |
-                StrictMode.DISALLOW_DISK_READ |
-                StrictMode.DISALLOW_NETWORK |
-                StrictMode.PENALTY_DROPBOX);
+              ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
+            StrictMode.conditionallyEnableDebugLogging();
         }
 
         /**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 7625c04..cd22fa1 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -588,7 +588,9 @@
      */
     private void updateVoiceButton(boolean empty) {
         int visibility = View.GONE;
-        if (mSearchable.getVoiceSearchEnabled() && empty) {
+        if ((mAppSearchData == null || !mAppSearchData.getBoolean(
+                SearchManager.DISABLE_VOICE_SEARCH, false))
+                && mSearchable.getVoiceSearchEnabled() && empty) {
             Intent testIntent = null;
             if (mSearchable.getVoiceSearchLaunchWebSearch()) {
                 testIntent = mVoiceWebSearchIntent;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index a1ca707..2e9cd96 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -395,6 +395,14 @@
     public final static String CONTEXT_IS_VOICE = "android.search.CONTEXT_IS_VOICE";
 
     /**
+     * This means that the voice icon should not be shown at all, because the
+     * current search engine does not support voice search.
+     * @hide
+     */
+    public final static String DISABLE_VOICE_SEARCH
+            = "android.search.DISABLE_VOICE_SEARCH";
+
+    /**
      * Reference to the shared system search service.
      */
     private static ISearchManager mService;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ef72013..4bd9bd9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -192,7 +192,7 @@
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the two packages have a matching signature.
+     * if all signatures on the two packages match.
      */
     public static final int SIGNATURE_MATCH = 0;
 
@@ -204,25 +204,25 @@
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the first package is not signed, but the second is.
+     * if the first package is not signed but the second is.
      */
     public static final int SIGNATURE_FIRST_NOT_SIGNED = -1;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if the second package is not signed, but the first is.
+     * if the second package is not signed but the first is.
      */
     public static final int SIGNATURE_SECOND_NOT_SIGNED = -2;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if both packages are signed but there is no matching signature.
+     * if not all signatures on both packages match.
      */
     public static final int SIGNATURE_NO_MATCH = -3;
 
     /**
      * Signature check result: this is returned by {@link #checkSignatures}
-     * if either of the given package names are not valid.
+     * if either of the packages are not valid.
      */
     public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
 
@@ -1230,20 +1230,14 @@
      *
      * @param pkg1 First package name whose signature will be compared.
      * @param pkg2 Second package name whose signature will be compared.
-     * @return Returns an integer indicating whether there is a matching
-     * signature: the value is >= 0 if there is a match (or neither package
-     * is signed), or < 0 if there is not a match.  The match result can be
-     * further distinguished with the success (>= 0) constants
-     * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
-     * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
-     * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
-     * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
+     *
+     * @return Returns an integer indicating whether all signatures on the
+     * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+     * all signatures match or < 0 if there is not a match ({@link
+     * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
      *
      * @see #checkSignatures(int, int)
      * @see #SIGNATURE_MATCH
-     * @see #SIGNATURE_NEITHER_SIGNED
-     * @see #SIGNATURE_FIRST_NOT_SIGNED
-     * @see #SIGNATURE_SECOND_NOT_SIGNED
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
@@ -1258,20 +1252,14 @@
      *
      * @param uid1 First UID whose signature will be compared.
      * @param uid2 Second UID whose signature will be compared.
-     * @return Returns an integer indicating whether there is a matching
-     * signature: the value is >= 0 if there is a match (or neither package
-     * is signed), or < 0 if there is not a match.  The match result can be
-     * further distinguished with the success (>= 0) constants
-     * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
-     * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
-     * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
-     * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
      *
-     * @see #checkSignatures(int, int)
+     * @return Returns an integer indicating whether all signatures on the
+     * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+     * all signatures match or < 0 if there is not a match ({@link
+     * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
+     *
+     * @see #checkSignatures(String, String)
      * @see #SIGNATURE_MATCH
-     * @see #SIGNATURE_NEITHER_SIGNED
-     * @see #SIGNATURE_FIRST_NOT_SIGNED
-     * @see #SIGNATURE_SECOND_NOT_SIGNED
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 9166019..b822b27 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -49,7 +49,6 @@
 import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
 import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
 
 /**
  * SSLSocketFactory implementation with several extra features:
@@ -211,7 +210,8 @@
     private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
         try {
             OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
-            sslContext.engineInit(null, trustManagers, null, mSessionCache, null);
+            sslContext.engineInit(null, trustManagers, null);
+            sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
             return sslContext.engineGetSocketFactory();
         } catch (KeyManagementException e) {
             Log.wtf(TAG, e);
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index c527fe4..4ca5903 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -19,7 +19,7 @@
 
 import com.android.internal.net.DomainNameValidator;
 
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
+import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
 
 import java.io.IOException;
 
@@ -191,7 +191,7 @@
         // report back to the user.
         //
         try {
-            SSLParameters.getDefaultTrustManager().checkServerTrusted(
+            SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(
                 newServerCertificates, "RSA");
 
             // no errors!!!
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index 8c9d013f..b361dca 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -98,7 +98,8 @@
                 }
             };
 
-            sslContext.engineInit(null, trustManagers, null, cache, null);
+            sslContext.engineInit(null, trustManagers, null);
+            sslContext.engineGetClientSessionContext().setPersistentCache(cache);
 
             synchronized (HttpsConnection.class) {
                 mSslSocketFactory = sslContext.engineGetSocketFactory();
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index d28148c..5fb1d7c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -129,7 +129,7 @@
 
     private static final int CORE_POOL_SIZE = 5;
     private static final int MAXIMUM_POOL_SIZE = 128;
-    private static final int KEEP_ALIVE = 10;
+    private static final int KEEP_ALIVE = 1;
 
     private static final BlockingQueue<Runnable> sWorkQueue =
             new LinkedBlockingQueue<Runnable>(10);
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 7f7b02b..f571c42 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -201,6 +201,25 @@
     }
 
     /**
+     * Enable DropBox logging for debug phone builds.
+     *
+     * @hide
+     */
+    public static boolean conditionallyEnableDebugLogging() {
+        // For debug builds, log event loop stalls to dropbox for analysis.
+        // Similar logic also appears in ActivityThread.java for system apps.
+        if ("user".equals(Build.TYPE)) {
+            return false;
+        }
+        StrictMode.setThreadPolicy(
+            StrictMode.DISALLOW_DISK_WRITE |
+            StrictMode.DISALLOW_DISK_READ |
+            StrictMode.DISALLOW_NETWORK |
+            StrictMode.PENALTY_DROPBOX);
+        return true;
+    }
+
+    /**
      * Parses the BlockGuard policy mask out from the Exception's
      * getMessage() String value.  Kinda gross, but least
      * invasive.  :/
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index bba1984..287c136 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -190,7 +190,7 @@
         for (int i2=0; i2<N2 && i1<N1; i2++) {
             if (uids2[i2] == uids1[i1]) {
                 N1--;
-                if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1-1, N1-i1);
+                if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1);
             }
             while (i1 < N1 && uids2[i2] > uids1[i1]) {
                 i1++;
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 9a09805..6355a9c 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -943,6 +943,80 @@
     }
 
     /**
+     * CalendarCache stores some settings for calendar including the current
+     * time zone for the app. These settings are stored using a key/value
+     * scheme.
+     */
+    public interface CalendarCacheColumns {
+        /**
+         * The key for the setting. Keys are defined in CalendarChache in the
+         * Calendar provider.
+         * TODO Add keys to this file
+         */
+        public static final String KEY = "key";
+
+        /**
+         * The value of the given setting.
+         */
+        public static final String VALUE = "value";
+    }
+
+    public static class CalendarCache implements CalendarCacheColumns {
+        /**
+         * The URI to use for retrieving the properties from the Calendar db.
+         */
+        public static final Uri URI =
+                Uri.parse("content://" + AUTHORITY + "/properties");
+        public static final String[] POJECTION = { KEY, VALUE };
+
+        /**
+         * If updating a property, this must be provided as the selection. All
+         * other selections will fail. For queries this field can be omitted to
+         * retrieve all properties or used to query a single property. Valid
+         * keys include {@link #TIMEZONE_KEY_TYPE},
+         * {@link #TIMEZONE_KEY_INSTANCES}, and
+         * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
+         * only be read, not written.
+         */
+        public static final String WHERE = "key=?";
+
+        /**
+         * They key for updating the use of auto/home time zones in Calendar.
+         * Valid values are {@link #TIMEZONE_TYPE_AUTO} or
+         * {@link #TIMEZONE_TYPE_HOME}.
+         */
+        public static final String TIMEZONE_KEY_TYPE = "timezoneType";
+
+        /**
+         * The key for updating the time zone used by the provider when it
+         * generates the instances table. This should only be written if the
+         * type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
+         * should be written to this field.
+         */
+        public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";
+
+        /**
+         * The key for reading the last time zone set by the user. This should
+         * only be read by apps and it will be automatically updated whenever
+         * {@link #TIMEZONE_KEY_INSTANCES} is updated with
+         * {@link #TIMEZONE_TYPE_HOME} set.
+         */
+        public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+
+        /**
+         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+         * should stay in sync with the device's time zone.
+         */
+        public static final String TIMEZONE_TYPE_AUTO = "auto";
+
+        /**
+         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+         * should use a fixed time zone set by the user.
+         */
+        public static final String TIMEZONE_TYPE_HOME = "home";
+    }
+
+    /**
      * A few Calendar globals are needed in the CalendarProvider for expanding
      * the Instances table and these are all stored in the first (and only)
      * row of the CalendarMetaData table.
diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java
new file mode 100644
index 0000000..9a4a67d
--- /dev/null
+++ b/core/java/android/util/CalendarUtils.java
@@ -0,0 +1,332 @@
+/*
+ * 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 android.util;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.provider.Calendar.CalendarCache;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Locale;
+
+/**
+ * A class containing utility methods related to Calendar apps.
+ *
+ * @hide
+ */
+public class CalendarUtils {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "CalendarUtils";
+
+    /**
+     * This class contains methods specific to reading and writing time zone
+     * values.
+     */
+    public static class TimeZoneUtils {
+        private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.TIMEZONE_KEY_TYPE };
+        private static final String[] TIMEZONE_INSTANCES_ARGS =
+                { CalendarCache.TIMEZONE_KEY_INSTANCES };
+
+        private static StringBuilder mSB = new StringBuilder(50);
+        private static Formatter mF = new Formatter(mSB, Locale.getDefault());
+        private volatile static boolean mFirstTZRequest = true;
+        private volatile static boolean mTZQueryInProgress = false;
+
+        private volatile static boolean mUseHomeTZ = false;
+        private volatile static String mHomeTZ = Time.getCurrentTimezone();
+
+        private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
+        private static int mToken = 1;
+        private static AsyncTZHandler mHandler;
+
+        // The name of the shared preferences file. This name must be maintained for historical
+        // reasons, as it's what PreferenceManager assigned the first time the file was created.
+        private final String mPrefsName;
+
+        /**
+         * This is the key used for writing whether or not a home time zone should
+         * be used in the Calendar app to the Calendar Preferences.
+         */
+        public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
+        /**
+         * This is the key used for writing the time zone that should be used if
+         * home time zones are enabled for the Calendar app.
+         */
+        public static final String KEY_HOME_TZ = "preferences_home_tz";
+
+        /**
+         * This is a helper class for handling the async queries and updates for the
+         * time zone settings in Calendar.
+         */
+        private class AsyncTZHandler extends AsyncQueryHandler {
+            public AsyncTZHandler(ContentResolver cr) {
+                super(cr);
+            }
+
+            @Override
+            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+                synchronized (mTZCallbacks) {
+                    boolean writePrefs = false;
+                    // Check the values in the db
+                    int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
+                    int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
+                    while(cursor.moveToNext()) {
+                        String key = cursor.getString(keyColumn);
+                        String value = cursor.getString(valueColumn);
+                        if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) {
+                            boolean useHomeTZ = !TextUtils.equals(
+                                    value, CalendarCache.TIMEZONE_TYPE_AUTO);
+                            if (useHomeTZ != mUseHomeTZ) {
+                                writePrefs = true;
+                                mUseHomeTZ = useHomeTZ;
+                            }
+                        } else if (TextUtils.equals(
+                                key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) {
+                            if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
+                                writePrefs = true;
+                                mHomeTZ = value;
+                            }
+                        }
+                    }
+                    if (writePrefs) {
+                        SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
+                        // Write the prefs
+                        setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+                        setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+                    }
+
+                    mTZQueryInProgress = false;
+                    for (Runnable callback : mTZCallbacks) {
+                        if (callback != null) {
+                            callback.run();
+                        }
+                    }
+                    mTZCallbacks.clear();
+                }
+            }
+        }
+
+        /**
+         * The name of the file where the shared prefs for Calendar are stored
+         * must be provided. All activities within an app should provide the
+         * same preferences name or behavior may become erratic.
+         *
+         * @param prefsName
+         */
+        public TimeZoneUtils(String prefsName) {
+            mPrefsName = prefsName;
+        }
+
+        /**
+         * Formats a date or a time range according to the local conventions.
+         *
+         * This formats a date/time range using Calendar's time zone and the
+         * local conventions for the region of the device.
+         *
+         * @param context the context is required only if the time is shown
+         * @param startMillis the start time in UTC milliseconds
+         * @param endMillis the end time in UTC milliseconds
+         * @param flags a bit mask of options See
+         * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
+         * @return a string containing the formatted date/time range.
+         */
+        public String formatDateRange(Context context, long startMillis,
+                long endMillis, int flags) {
+            String date;
+            synchronized (mSB) {
+                mSB.setLength(0);
+                date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
+                        getTimeZone(context, null)).toString();
+            }
+            return date;
+        }
+
+        /**
+         * Writes a new home time zone to the db.
+         *
+         * Updates the home time zone in the db asynchronously and updates
+         * the local cache. Sending a time zone of
+         * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set
+         * to the device's time zone. null or empty tz will be ignored.
+         *
+         * @param context The calling activity
+         * @param timeZone The time zone to set Calendar to, or
+         * {@link CalendarCache#TIMEZONE_TYPE_AUTO}
+         */
+        public void setTimeZone(Context context, String timeZone) {
+            if (TextUtils.isEmpty(timeZone)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Empty time zone, nothing to be done.");
+                }
+                return;
+            }
+            boolean updatePrefs = false;
+            synchronized (mTZCallbacks) {
+                if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) {
+                    if (mUseHomeTZ) {
+                        updatePrefs = true;
+                    }
+                    mUseHomeTZ = false;
+                } else {
+                    if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) {
+                        updatePrefs = true;
+                    }
+                    mUseHomeTZ = true;
+                    mHomeTZ = timeZone;
+                }
+            }
+            if (updatePrefs) {
+                // Write the prefs
+                SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+                setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+                setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+
+                // Update the db
+                ContentValues values = new ContentValues();
+                if (mHandler == null) {
+                    mHandler = new AsyncTZHandler(context.getContentResolver());
+                }
+
+                mHandler.cancelOperation(mToken);
+
+                // skip 0 so query can use it
+                if (++mToken == 0) {
+                    mToken = 1;
+                }
+
+                // Write the use home tz setting
+                values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME
+                        : CalendarCache.TIMEZONE_TYPE_AUTO);
+                mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE,
+                        TIMEZONE_TYPE_ARGS);
+
+                // If using a home tz write it to the db
+                if (mUseHomeTZ) {
+                    ContentValues values2 = new ContentValues();
+                    values2.put(CalendarCache.VALUE, mHomeTZ);
+                    mHandler.startUpdate(mToken, null, CalendarCache.URI, values2,
+                            CalendarCache.WHERE, TIMEZONE_INSTANCES_ARGS);
+                }
+            }
+        }
+
+        /**
+         * Gets the time zone that Calendar should be displayed in
+         *
+         * This is a helper method to get the appropriate time zone for Calendar. If this
+         * is the first time this method has been called it will initiate an asynchronous
+         * query to verify that the data in preferences is correct. The callback supplied
+         * will only be called if this query returns a value other than what is stored in
+         * preferences and should cause the calling activity to refresh anything that
+         * depends on calling this method.
+         *
+         * @param context The calling activity
+         * @param callback The runnable that should execute if a query returns new values
+         * @return The string value representing the time zone Calendar should display
+         */
+        public String getTimeZone(Context context, Runnable callback) {
+            synchronized (mTZCallbacks){
+                if (mFirstTZRequest) {
+                    mTZQueryInProgress = true;
+                    mFirstTZRequest = false;
+
+                    SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+                    mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false);
+                    mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());
+
+                    // When the async query returns it should synchronize on
+                    // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
+                    // preferences, set mTZQueryInProgress to false, and call all
+                    // the runnables in mTZCallbacks.
+                    if (mHandler == null) {
+                        mHandler = new AsyncTZHandler(context.getContentResolver());
+                    }
+                    mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION,
+                            null, null, null);
+                }
+                if (mTZQueryInProgress) {
+                    mTZCallbacks.add(callback);
+                }
+            }
+            return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
+        }
+
+        /**
+         * Forces a query of the database to check for changes to the time zone.
+         * This should be called if another app may have modified the db. If a
+         * query is already in progress the callback will be added to the list
+         * of callbacks to be called when it returns.
+         *
+         * @param context The calling activity
+         * @param callback The runnable that should execute if a query returns
+         *            new values
+         */
+        public void forceDBRequery(Context context, Runnable callback) {
+            synchronized (mTZCallbacks){
+                if (mTZQueryInProgress) {
+                    mTZCallbacks.add(callback);
+                    return;
+                }
+                mFirstTZRequest = true;
+                getTimeZone(context, callback);
+            }
+        }
+    }
+
+        /**
+         * A helper method for writing a String value to the preferences
+         * asynchronously.
+         *
+         * @param context A context with access to the correct preferences
+         * @param key The preference to write to
+         * @param value The value to write
+         */
+        public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
+//            SharedPreferences prefs = getSharedPreferences(context);
+            SharedPreferences.Editor editor = prefs.edit();
+            editor.putString(key, value);
+            editor.apply();
+        }
+
+        /**
+         * A helper method for writing a boolean value to the preferences
+         * asynchronously.
+         *
+         * @param context A context with access to the correct preferences
+         * @param key The preference to write to
+         * @param value The value to write
+         */
+        public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
+//            SharedPreferences prefs = getSharedPreferences(context, prefsName);
+            SharedPreferences.Editor editor = prefs.edit();
+            editor.putBoolean(key, value);
+            editor.apply();
+        }
+
+        /** Return a properly configured SharedPreferences instance */
+        public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
+            return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
+        }
+}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 2517a8a..6aa77f6 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -28,7 +28,7 @@
 #include <surfaceflinger/Surface.h>
 #include <ui/egl/android_natives.h>
 #include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 #include "JNIHelp.h"
 #include "android_os_MessageQueue.h"
@@ -128,17 +128,17 @@
 }
 
 void AInputQueue::attachLooper(ALooper* looper, int ident,
-        ALooper_callbackFunc* callback, void* data) {
-    mPollLoop = static_cast<android::PollLoop*>(looper);
-    mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
-            ident, POLLIN, callback, data);
-    mPollLoop->setLooperCallback(mDispatchKeyRead,
-            ident, POLLIN, callback, data);
+        ALooper_callbackFunc callback, void* data) {
+    mLooper = static_cast<android::Looper*>(looper);
+    mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+            ident, ALOOPER_EVENT_INPUT, callback, data);
+    mLooper->addFd(mDispatchKeyRead,
+            ident, ALOOPER_EVENT_INPUT, callback, data);
 }
 
 void AInputQueue::detachLooper() {
-    mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
-    mPollLoop->removeCallback(mDispatchKeyRead);
+    mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+    mLooper->removeFd(mDispatchKeyRead);
 }
 
 int32_t AInputQueue::hasEvents() {
@@ -440,8 +440,8 @@
         if (env != NULL && clazz != NULL) {
             env->DeleteGlobalRef(clazz);
         }
-        if (pollLoop != NULL && mainWorkRead >= 0) {
-            pollLoop->removeCallback(mainWorkRead);
+        if (looper != NULL && mainWorkRead >= 0) {
+            looper->removeFd(mainWorkRead);
         }
         if (nativeInputQueue != NULL) {
             nativeInputQueue->mWorkWrite = -1;
@@ -509,7 +509,7 @@
     // These are used to wake up the main thread to process work.
     int mainWorkRead;
     int mainWorkWrite;
-    sp<PollLoop> pollLoop;
+    sp<Looper> looper;
 };
 
 void android_NativeActivity_setWindowFormat(
@@ -541,15 +541,15 @@
 /*
  * Callback for handling native events on the application's main thread.
  */
-static bool mainWorkCallback(int fd, int events, void* data) {
+static int mainWorkCallback(int fd, int events, void* data) {
     NativeCode* code = (NativeCode*)data;
     if ((events & POLLIN) == 0) {
-        return true;
+        return 1;
     }
     
     ActivityWork work;
     if (!read_work(code->mainWorkRead, &work)) {
-        return true;
+        return 1;
     }
 
     LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
@@ -593,7 +593,7 @@
             break;
     }
     
-    return true;
+    return 1;
 }
 
 // ------------------------------------------------------------------------
@@ -621,9 +621,9 @@
             return 0;
         }
         
-        code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue);
-        if (code->pollLoop == NULL) {
-            LOGW("Unable to retrieve MessageQueue's PollLoop");
+        code->looper = android_os_MessageQueue_getLooper(env, messageQueue);
+        if (code->looper == NULL) {
+            LOGW("Unable to retrieve MessageQueue's Looper");
             delete code;
             return 0;
         }
@@ -642,7 +642,7 @@
         result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
         SLOGW_IF(result != 0, "Could not make main work write pipe "
                 "non-blocking: %s", strerror(errno));
-        code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
+        code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
         
         code->ANativeActivity::callbacks = &code->callbacks;
         if (env->GetJavaVM(&code->vm) < 0) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e29495c..10ceb7b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -60,7 +60,7 @@
 
     Sensor const* const* sensorList;
     size_t count = mgr.getSensorList(&sensorList);
-    if (next >= count)
+    if (size_t(next) >= count)
         return -1;
     
     Sensor const* const list = sensorList[next];
@@ -78,7 +78,7 @@
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     
     next++;
-    return next<count ? next : 0;
+    return size_t(next) < count ? next : 0;
 }
 
 //----------------------------------------------------------------------------
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 847b5a5..1b203ca 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -18,7 +18,7 @@
 
 #include "JNIHelp.h"
 
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Log.h>
 #include "android_os_MessageQueue.h"
 
@@ -39,22 +39,22 @@
     NativeMessageQueue();
     ~NativeMessageQueue();
 
-    inline sp<PollLoop> getPollLoop() { return mPollLoop; }
+    inline sp<Looper> getLooper() { return mLooper; }
 
     bool pollOnce(int timeoutMillis);
     void wake();
 
 private:
-    sp<PollLoop> mPollLoop;
+    sp<Looper> mLooper;
 };
 
 // ----------------------------------------------------------------------------
 
 NativeMessageQueue::NativeMessageQueue() {
-    mPollLoop = PollLoop::getForThread();
-    if (mPollLoop == NULL) {
-        mPollLoop = new PollLoop(false);
-        PollLoop::setForThread(mPollLoop);
+    mLooper = Looper::getForThread();
+    if (mLooper == NULL) {
+        mLooper = new Looper(false);
+        Looper::setForThread(mLooper);
     }
 }
 
@@ -62,11 +62,11 @@
 }
 
 bool NativeMessageQueue::pollOnce(int timeoutMillis) {
-    return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
+    return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
 }
 
 void NativeMessageQueue::wake() {
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 // ----------------------------------------------------------------------------
@@ -83,10 +83,10 @@
              reinterpret_cast<jint>(nativeMessageQueue));
 }
 
-sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj) {
+sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) {
     NativeMessageQueue* nativeMessageQueue =
             android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
-    return nativeMessageQueue != NULL ? nativeMessageQueue->getPollLoop() : NULL;
+    return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL;
 }
 
 static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h
index 5c742e2..f961d8f 100644
--- a/core/jni/android_os_MessageQueue.h
+++ b/core/jni/android_os_MessageQueue.h
@@ -21,9 +21,9 @@
 
 namespace android {
 
-class PollLoop;
+class Looper;
 
-extern sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj);
+extern sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj);
 
 } // namespace android
 
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 42f35d1..282e9ed 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -29,7 +29,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <ui/InputTransport.h>
@@ -77,7 +77,7 @@
         };
 
         Connection(uint16_t id,
-                const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
+                const sp<InputChannel>& inputChannel, const sp<Looper>& looper);
 
         inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
 
@@ -88,7 +88,7 @@
 
         sp<InputChannel> inputChannel;
         InputConsumer inputConsumer;
-        sp<PollLoop> pollLoop;
+        sp<Looper> looper;
         jobject inputHandlerObjGlobal;
         PreallocatedInputEventFactory inputEventFactory;
 
@@ -110,7 +110,7 @@
     static void handleInputChannelDisposed(JNIEnv* env,
             jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
 
-    static bool handleReceiveCallback(int receiveFd, int events, void* data);
+    static int handleReceiveCallback(int receiveFd, int events, void* data);
 
     static jlong generateFinishedToken(int32_t receiveFd,
             uint16_t connectionId, uint16_t messageSeqNum);
@@ -141,7 +141,7 @@
     LOGD("channel '%s' - Registered", inputChannel->getName().string());
 #endif
 
-    sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj);
+    sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
 
     { // acquire lock
         AutoMutex _l(mLock);
@@ -153,7 +153,7 @@
         }
 
         uint16_t connectionId = mNextConnectionId++;
-        sp<Connection> connection = new Connection(connectionId, inputChannel, pollLoop);
+        sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
         status_t result = connection->inputConsumer.initialize();
         if (result) {
             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
@@ -166,7 +166,7 @@
         int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
 
-        pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+        looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
     } // release lock
 
     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
@@ -201,7 +201,7 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
-        connection->pollLoop->removeCallback(inputChannel->getReceivePipeFd());
+        connection->looper->removeFd(inputChannel->getReceivePipeFd());
 
         env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
         connection->inputHandlerObjGlobal = NULL;
@@ -293,7 +293,7 @@
     q->unregisterInputChannel(env, inputChannelObj);
 }
 
-bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
+int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
     NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
@@ -308,33 +308,33 @@
         if (connectionIndex < 0) {
             LOGE("Received spurious receive callback for unknown input channel.  "
                     "fd=%d, events=0x%x", receiveFd, events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
-        if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+        if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
             LOGE("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
-        if (! (events & POLLIN)) {
+        if (! (events & ALOOPER_EVENT_INPUT)) {
             LOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return true;
+            return 1;
         }
 
         status_t status = connection->inputConsumer.receiveDispatchSignal();
         if (status) {
             LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
                     connection->getInputChannelName(), status);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         if (connection->messageInProgress) {
             LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
                     connection->getInputChannelName());
-            return true;
+            return 1;
         }
 
         status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
@@ -342,7 +342,7 @@
             LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
                     connection->getInputChannelName(), status);
             connection->inputConsumer.sendFinishedSignal();
-            return true;
+            return 1;
         }
 
         connection->messageInProgress = true;
@@ -394,7 +394,7 @@
                 connection->getInputChannelName());
         env->DeleteLocalRef(inputHandlerObjLocal);
         q->finished(env, finishedToken, false);
-        return true;
+        return 1;
     }
 
 #if DEBUG_DISPATCH_CYCLE
@@ -417,7 +417,7 @@
 
     env->DeleteLocalRef(inputEventObj);
     env->DeleteLocalRef(inputHandlerObjLocal);
-    return true;
+    return 1;
 }
 
 jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
@@ -435,9 +435,9 @@
 // ----------------------------------------------------------------------------
 
 NativeInputQueue::Connection::Connection(uint16_t id,
-        const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) :
+        const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
     id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
-    pollLoop(pollLoop), inputHandlerObjGlobal(NULL),
+    looper(looper), inputHandlerObjGlobal(NULL),
     messageSeqNum(0), messageInProgress(false) {
 }
 
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index fdceb84..b49e02a 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -18,6 +18,7 @@
 #define _ANDROID_APP_NATIVEACTIVITY_H
 
 #include <ui/InputTransport.h>
+#include <utils/Looper.h>
 
 #include <android/native_activity.h>
 
@@ -69,7 +70,7 @@
     /* Destroys the consumer and releases its input channel. */
     ~AInputQueue();
 
-    void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+    void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
 
     void detachLooper();
 
@@ -103,7 +104,7 @@
     void wakeupDispatch();
 
     android::InputConsumer mConsumer;
-    android::sp<android::PollLoop> mPollLoop;
+    android::sp<android::Looper> mLooper;
 
     int mDispatchKeyRead;
     int mDispatchKeyWrite;
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index 6581ae3..97dd391 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -42,7 +42,7 @@
 
 class ISensorEventConnection;
 class Sensor;
-class PollLoop;
+class Looper;
 
 // ----------------------------------------------------------------------------
 
@@ -69,11 +69,11 @@
     status_t disableSensor(int32_t handle) const;
 
 private:
-    sp<PollLoop> getPollLoop() const;
+    sp<Looper> getLooper() const;
     sp<ISensorEventConnection> mSensorEventConnection;
     sp<SensorChannel> mSensorChannel;
     mutable Mutex mLock;
-    mutable sp<PollLoop> mPollLoop;
+    mutable sp<Looper> mLooper;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 0f4594f..c913355 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -56,6 +56,9 @@
     status_t setUpdateRectangle(const Rect& updateRect);
     status_t compositionComplete();
     
+    // for debugging only
+    int getCurrentBufferIndex() const;
+
 private:
     friend class LightRefBase<FramebufferNativeWindow>;    
     ~FramebufferNativeWindow(); // this class cannot be overloaded
@@ -77,6 +80,7 @@
     int32_t mNumBuffers;
     int32_t mNumFreeBuffers;
     int32_t mBufferHead;
+    int32_t mCurrentBufferIndex;
     bool mUpdateOnDemand;
 };
     
diff --git a/include/ui/GraphicLog.h b/include/ui/GraphicLog.h
new file mode 100644
index 0000000..f929e6a
--- /dev/null
+++ b/include/ui/GraphicLog.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef _UI_GRAPHIC_LOG_H
+#define _UI_GRAPHIC_LOG_H
+
+#include <utils/Singleton.h>
+#include <cutils/compiler.h>
+
+namespace android {
+
+class GraphicLog : public Singleton<GraphicLog>
+{
+    int32_t mEnabled;
+    static void logImpl(int32_t tag, int32_t buffer);
+    static void logImpl(int32_t tag, int32_t identity, int32_t buffer);
+
+public:
+    enum {
+        SF_APP_DEQUEUE_BEFORE   = 60000,
+        SF_APP_DEQUEUE_AFTER    = 60001,
+        SF_APP_LOCK_BEFORE      = 60002,
+        SF_APP_LOCK_AFTER       = 60003,
+        SF_APP_QUEUE            = 60004,
+
+        SF_REPAINT              = 60005,
+        SF_COMPOSITION_COMPLETE = 60006,
+        SF_UNLOCK_CLIENTS       = 60007,
+        SF_SWAP_BUFFERS         = 60008,
+        SF_REPAINT_DONE         = 60009,
+
+        SF_FB_POST_BEFORE       = 60010,
+        SF_FB_POST_AFTER        = 60011,
+        SF_FB_DEQUEUE_BEFORE    = 60012,
+        SF_FB_DEQUEUE_AFTER     = 60013,
+        SF_FB_LOCK_BEFORE       = 60014,
+        SF_FB_LOCK_AFTER        = 60015,
+    };
+
+    inline void log(int32_t tag, int32_t buffer) {
+        if (CC_UNLIKELY(mEnabled))
+            logImpl(tag, buffer);
+    }
+    inline void log(int32_t tag, int32_t identity, int32_t buffer) {
+        if (CC_UNLIKELY(mEnabled))
+            logImpl(tag, identity, buffer);
+    }
+
+    GraphicLog();
+
+    void setEnabled(bool enable);
+};
+
+}
+
+#endif // _UI_GRAPHIC_LOG_H
+
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index a06208a..d7e6254 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -25,7 +25,7 @@
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Pool.h>
 
 #include <stddef.h>
@@ -826,7 +826,7 @@
     Mutex mLock;
 
     Allocator mAllocator;
-    sp<PollLoop> mPollLoop;
+    sp<Looper> mLooper;
 
     EventEntry* mPendingEvent;
     Queue<EventEntry> mInboundQueue;
@@ -837,7 +837,7 @@
     void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
             nsecs_t* nextWakeupTime);
 
-    // Enqueues an inbound event.  Returns true if mPollLoop->wake() should be called.
+    // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
     bool enqueueInboundEventLocked(EventEntry* entry);
 
     // App switch latency optimization.
@@ -1010,7 +1010,7 @@
     void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             bool broken);
     void drainOutboundQueueLocked(Connection* connection, DispatchEntry* firstDispatchEntryToDrain);
-    static bool handleReceiveCallback(int receiveFd, int events, void* data);
+    static int handleReceiveCallback(int receiveFd, int events, void* data);
 
     // Preempting input dispatch.
     bool preemptInputDispatchInnerLocked();
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 82831e29..dc9e27a 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -33,7 +33,6 @@
 #include <semaphore.h>
 #include <ui/Input.h>
 #include <utils/Errors.h>
-#include <utils/PollLoop.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
new file mode 100644
index 0000000..92e4b0a
--- /dev/null
+++ b/include/utils/Looper.h
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#ifndef UTILS_LOOPER_H
+#define UTILS_LOOPER_H
+
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+#include <android/looper.h>
+
+/*
+ * Declare a concrete type for the NDK's looper forward declaration.
+ */
+struct ALooper {
+};
+
+namespace android {
+
+/**
+ * A polling loop that supports monitoring file descriptor events, optionally
+ * using callbacks.  The implementation uses epoll() internally.
+ *
+ * A looper can be associated with a thread although there is no requirement that it must be.
+ */
+class Looper : public ALooper, public RefBase {
+protected:
+    virtual ~Looper();
+
+public:
+    /**
+     * Creates a looper.
+     *
+     * If allowNonCallbaks is true, the looper will allow file descriptors to be
+     * registered without associated callbacks.  This assumes that the caller of
+     * pollOnce() is prepared to handle callback-less events itself.
+     */
+    Looper(bool allowNonCallbacks);
+
+    /**
+     * Returns whether this looper instance allows the registration of file descriptors
+     * using identifiers instead of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+
+    /**
+     * Waits for events to be available, with optional timeout in milliseconds.
+     * Invokes callbacks for all file descriptors on which an event occurred.
+     *
+     * If the timeout is zero, returns immediately without blocking.
+     * If the timeout is negative, waits indefinitely until an event appears.
+     *
+     * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+     * the timeout expired and no callbacks were invoked and no other file
+     * descriptors were ready.
+     *
+     * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+     *
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing an identifier if its file descriptor has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outFd, outEvents and outData will contain the poll
+     * events and data associated with the fd, otherwise they will be set to NULL.
+     *
+     * This method does not return until it has finished invoking the appropriate callbacks
+     * for all file descriptors that were signalled.
+     */
+    int pollOnce(int timeoutMillis,
+            int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);
+
+    /**
+     * Like pollOnce(), but performs all pending callbacks until all
+     * data has been consumed or a file descriptor is available with no callback.
+     * This function will never return ALOOPER_POLL_CALLBACK.
+     */
+    int pollAll(int timeoutMillis,
+            int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);
+
+    /**
+     * Wakes the poll asynchronously.
+     *
+     * This method can be called on any thread.
+     * This method returns immediately.
+     */
+    void wake();
+
+    /**
+     * Adds a new file descriptor to be polled by the looper.
+     * If the same file descriptor was previously added, it is replaced.
+     *
+     * "fd" is the file descriptor to be added.
+     * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+     * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+     * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
+     * "callback" is the function to call when there is an event on the file descriptor.
+     * "data" is a private data pointer to supply to the callback.
+     *
+     * There are two main uses of this function:
+     *
+     * (1) If "callback" is non-NULL, then this function will be called when there is
+     * data on the file descriptor.  It should execute any events it has pending,
+     * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
+     *
+     * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+     * when its file descriptor has data available, requiring the caller to take
+     * care of processing it.
+     *
+     * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     */
+    int addFd(int fd, int ident,
+            int events, ALooper_callbackFunc callback, void* data = NULL);
+
+    /**
+     * Removes a previously added file descriptor from the looper.
+     *
+     * When this method returns, it is safe to close the file descriptor since the looper
+     * will no longer have a reference to it.  However, it is possible for the callback to
+     * already be running or for it to run one last time if the file descriptor was already
+     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
+     * For example, if the callback takes care of removing itself during its own execution either
+     * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+     * again at any later time unless registered anew.
+     *
+     * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
+     *
+     * This method can be called on any thread.
+     * This method may block briefly if it needs to wake the poll.
+     */
+    int removeFd(int fd);
+
+    /**
+     * Prepares a looper associated with the calling thread, and returns it.
+     * If the thread already has a looper, it is returned.  Otherwise, a new
+     * one is created, associated with the thread, and returned.
+     *
+     * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+     */
+    static sp<Looper> prepare(int opts);
+
+    /**
+     * Sets the given looper to be associated with the calling thread.
+     * If another looper is already associated with the thread, it is replaced.
+     *
+     * If "looper" is NULL, removes the currently associated looper.
+     */
+    static void setForThread(const sp<Looper>& looper);
+
+    /**
+     * Returns the looper associated with the calling thread, or NULL if
+     * there is not one.
+     */
+    static sp<Looper> getForThread();
+
+private:
+    struct Request {
+        int fd;
+        int ident;
+        ALooper_callbackFunc callback;
+        void* data;
+    };
+
+    struct Response {
+        int events;
+        Request request;
+    };
+
+    const bool mAllowNonCallbacks; // immutable
+
+    int mEpollFd; // immutable
+    int mWakeReadPipeFd;  // immutable
+    int mWakeWritePipeFd; // immutable
+
+    // Locked list of file descriptor monitoring requests.
+    Mutex mLock;
+    KeyedVector<int, Request> mRequests;
+
+    // This state is only used privately by pollOnce and does not require a lock since
+    // it runs on a single thread.
+    Vector<Response> mResponses;
+    size_t mResponseIndex;
+
+    int pollInner(int timeoutMillis);
+
+    static void threadDestructor(void *st);
+};
+
+} // namespace android
+
+#endif // UTILS_LOOPER_H
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
deleted file mode 100644
index c2dfe5d..0000000
--- a/include/utils/PollLoop.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef UTILS_POLL_LOOP_H
-#define UTILS_POLL_LOOP_H
-
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#include <sys/poll.h>
-
-#include <android/looper.h>
-
-struct ALooper : public android::RefBase {
-protected:
-    virtual ~ALooper() { }
-
-public:
-    ALooper() { }
-};
-
-namespace android {
-
-/**
- * A basic file descriptor polling loop based on poll() with callbacks.
- */
-class PollLoop : public ALooper {
-protected:
-    virtual ~PollLoop();
-
-public:
-    PollLoop(bool allowNonCallbacks);
-
-    /**
-     * A callback that it to be invoked when an event occurs on a file descriptor.
-     * Specifies the events that were triggered and the user data provided when the
-     * callback was set.
-     *
-     * Returns true if the callback should be kept, false if it should be removed automatically
-     * after the callback returns.
-     */
-    typedef bool (*Callback)(int fd, int events, void* data);
-
-    enum {
-        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
-        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
-        POLL_ERROR = ALOOPER_POLL_ERROR,
-    };
-    
-    /**
-     * Performs a single call to poll() with optional timeout in milliseconds.
-     * Invokes callbacks for all file descriptors on which an event occurred.
-     *
-     * If the timeout is zero, returns immediately without blocking.
-     * If the timeout is negative, waits indefinitely until awoken.
-     *
-     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
-     *
-     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
-     * timeout expired.
-     *
-     * Returns ALOPER_POLL_ERROR if an error occurred.
-     *
-     * Returns a value >= 0 containing a file descriptor if it has data
-     * and it has no callback function (requiring the caller here to handle it).
-     * In this (and only this) case outEvents and outData will contain the poll
-     * events and data associated with the fd.
-     *
-     * This method must only be called on the thread owning the PollLoop.
-     * This method blocks until either a file descriptor is signalled, a timeout occurs,
-     * or wake() is called.
-     * This method does not return until it has finished invoking the appropriate callbacks
-     * for all file descriptors that were signalled.
-     */
-    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
-
-    /**
-     * Wakes the loop asynchronously.
-     *
-     * This method can be called on any thread.
-     * This method returns immediately.
-     */
-    void wake();
-
-    /**
-     * Control whether this PollLoop instance allows using IDs instead
-     * of callbacks.
-     */
-    bool getAllowNonCallbacks() const;
-    
-    /**
-     * Sets the callback for a file descriptor, replacing the existing one, if any.
-     * It is an error to call this method with events == 0 or callback == NULL.
-     *
-     * Note that a callback can be invoked with the POLLERR, POLLHUP or POLLNVAL events
-     * even if it is not explicitly requested when registered.
-     *
-     * This method can be called on any thread.
-     * This method may block briefly if it needs to wake the poll loop.
-     */
-    void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);
-
-    /**
-     * Convenience for above setCallback when ident is not used.  In this case
-     * the ident is set to POLL_CALLBACK.
-     */
-    void setCallback(int fd, int events, Callback callback, void* data = NULL);
-    
-    /**
-     * Like setCallback(), but for the NDK callback function.
-     */
-    void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
-            void* data);
-    
-    /**
-     * Removes the callback for a file descriptor, if one exists.
-     *
-     * When this method returns, it is safe to close the file descriptor since the poll loop
-     * will no longer have a reference to it.  However, it is possible for the callback to
-     * already be running or for it to run one last time if the file descriptor was already
-     * signalled.  Calling code is responsible for ensuring that this case is safely handled.
-     * For example, if the callback takes care of removing itself during its own execution either
-     * by returning false or calling this method, then it can be guaranteed to not be invoked
-     * again at any later time unless registered anew.
-     *
-     * This method can be called on any thread.
-     * This method may block briefly if it needs to wake the poll loop.
-     *
-     * Returns true if a callback was actually removed, false if none was registered.
-     */
-    bool removeCallback(int fd);
-
-    /**
-     * Set the given PollLoop to be associated with the
-     * calling thread.  There must be a 1:1 relationship between
-     * PollLoop and thread.
-     */
-    static void setForThread(const sp<PollLoop>& pollLoop);
-    
-    /**
-     * Return the PollLoop associated with the calling thread.
-     */
-    static sp<PollLoop> getForThread();
-    
-private:
-    struct RequestedCallback {
-        Callback callback;
-        ALooper_callbackFunc* looperCallback;
-        int ident;
-        void* data;
-    };
-
-    struct PendingCallback {
-        int fd;
-        int ident;
-        int events;
-        Callback callback;
-        ALooper_callbackFunc* looperCallback;
-        void* data;
-    };
-    
-    const bool mAllowNonCallbacks; // immutable
-
-    int mWakeReadPipeFd;  // immutable
-    int mWakeWritePipeFd; // immutable
-
-    // The lock guards state used to track whether there is a poll() in progress and whether
-    // there are any other threads waiting in wakeAndLock().  The condition variables
-    // are used to transfer control among these threads such that all waiters are
-    // serviced before a new poll can begin.
-    // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
-    // until mPolling becomes false, then decrements mWaiters again.
-    // The poll() method blocks on mResume until mWaiters becomes 0, then sets
-    // mPolling to true, blocks until the poll completes, then resets mPolling to false
-    // and signals mResume if there are waiters.
-    Mutex mLock;
-    bool mPolling;      // guarded by mLock
-    uint32_t mWaiters;  // guarded by mLock
-    Condition mAwake;   // guarded by mLock
-    Condition mResume;  // guarded by mLock
-
-    // The next two vectors are only mutated when mPolling is false since they must
-    // not be changed while the poll() system call is in progress.  To mutate these
-    // vectors, the poll() must first be awoken then the lock acquired.
-    Vector<struct pollfd> mRequestedFds;
-    Vector<RequestedCallback> mRequestedCallbacks;
-
-    // This state is only used privately by pollOnce and does not require a lock since
-    // it runs on a single thread.
-    Vector<PendingCallback> mPendingCallbacks;
-    Vector<PendingCallback> mPendingFds;
-    size_t mPendingFdsPos;
-    
-    void openWakePipe();
-    void closeWakePipe();
-
-    void setCallbackCommon(int fd, int ident, int events, Callback callback,
-            ALooper_callbackFunc* looperCallback, void* data);
-    ssize_t getRequestIndexLocked(int fd);
-    void wakeAndLock();
-    static void threadDestructor(void *st);
-};
-
-} // namespace android
-
-#endif // UTILS_POLL_LOOP_H
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 7eb6da5..c3a9f22 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -21,7 +21,7 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 #include <gui/Sensor.h>
 #include <gui/SensorChannel.h>
@@ -81,28 +81,28 @@
     return size;
 }
 
-sp<PollLoop> SensorEventQueue::getPollLoop() const
+sp<Looper> SensorEventQueue::getLooper() const
 {
     Mutex::Autolock _l(mLock);
-    if (mPollLoop == 0) {
-        mPollLoop = new PollLoop(true);
-        mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
+    if (mLooper == 0) {
+        mLooper = new Looper(true);
+        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
     }
-    return mPollLoop;
+    return mLooper;
 }
 
 status_t SensorEventQueue::waitForEvent() const
 {
     const int fd = getFd();
-    sp<PollLoop> pollLoop(getPollLoop());
-    int32_t result = pollLoop->pollOnce(-1, NULL, NULL);
-    return (result == fd) ? NO_ERROR : -1;
+    sp<Looper> looper(getLooper());
+    int32_t result = looper->pollOnce(-1);
+    return (result == fd) ? status_t(NO_ERROR) : status_t(-1);
 }
 
 status_t SensorEventQueue::wake() const
 {
-    sp<PollLoop> pollLoop(getPollLoop());
-    pollLoop->wake();
+    sp<Looper> looper(getLooper());
+    looper->wake();
     return NO_ERROR;
 }
 
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index cb76091..560ea67 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -32,6 +32,7 @@
 #include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferMapper.h>
+#include <ui/GraphicLog.h>
 #include <ui/Rect.h>
 
 #include <surfaceflinger/Surface.h>
@@ -568,7 +569,13 @@
     if (err != NO_ERROR)
         return err;
 
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
+
     ssize_t bufIdx = mSharedBufferClient->dequeue();
+
+    logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
+
     if (bufIdx < 0) {
         LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
         return bufIdx;
@@ -617,13 +624,20 @@
         return err;
 
     int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
+
     err = mSharedBufferClient->lock(bufIdx);
+
+    logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
+
     LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
     return err;
 }
 
 int Surface::queueBuffer(android_native_buffer_t* buffer)
-{   
+{
     status_t err = validate();
     if (err != NO_ERROR)
         return err;
@@ -633,6 +647,9 @@
     }
     
     int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+    GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
+
     mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
     mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
     mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 9f49348..c4a09d6 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -9,6 +9,7 @@
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
+	GraphicLog.cpp \
 	KeyLayoutMap.cpp \
 	KeyCharacterMap.cpp \
 	Input.cpp \
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 6f8948d..a36d555 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -29,6 +29,7 @@
 
 #include <ui/Rect.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicLog.h>
 
 #include <EGL/egl.h>
 
@@ -174,6 +175,14 @@
     return fb->setSwapInterval(fb, interval);
 }
 
+// only for debugging / logging
+int FramebufferNativeWindow::getCurrentBufferIndex() const
+{
+    Mutex::Autolock _l(mutex);
+    const int index = mCurrentBufferIndex;
+    return index;
+}
+
 int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 
         android_native_buffer_t** buffer)
 {
@@ -181,18 +190,24 @@
     Mutex::Autolock _l(self->mutex);
     framebuffer_device_t* fb = self->fbDev;
 
+    int index = self->mBufferHead++;
+    if (self->mBufferHead >= self->mNumBuffers)
+        self->mBufferHead = 0;
+
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index);
+
     // wait for a free buffer
     while (!self->mNumFreeBuffers) {
         self->mCondition.wait(self->mutex);
     }
     // get this buffer
     self->mNumFreeBuffers--;
-    int index = self->mBufferHead++;
-    if (self->mBufferHead >= self->mNumBuffers)
-        self->mBufferHead = 0;
+    self->mCurrentBufferIndex = index;
 
     *buffer = self->buffers[index].get();
 
+    logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index);
     return 0;
 }
 
@@ -202,11 +217,17 @@
     FramebufferNativeWindow* self = getSelf(window);
     Mutex::Autolock _l(self->mutex);
 
+    const int index = self->mCurrentBufferIndex;
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index);
+
     // wait that the buffer we're locking is not front anymore
     while (self->front == buffer) {
         self->mCondition.wait(self->mutex);
     }
 
+    logger.log(GraphicLog::SF_FB_LOCK_AFTER, index);
+
     return NO_ERROR;
 }
 
@@ -217,7 +238,15 @@
     Mutex::Autolock _l(self->mutex);
     framebuffer_device_t* fb = self->fbDev;
     buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+
+    const int index = self->mCurrentBufferIndex;
+    GraphicLog& logger(GraphicLog::getInstance());
+    logger.log(GraphicLog::SF_FB_POST_BEFORE, index);
+
     int res = fb->post(fb, handle);
+
+    logger.log(GraphicLog::SF_FB_POST_AFTER, index);
+
     self->front = static_cast<NativeBuffer*>(buffer);
     self->mNumFreeBuffers++;
     self->mCondition.broadcast();
diff --git a/libs/ui/GraphicLog.cpp b/libs/ui/GraphicLog.cpp
new file mode 100644
index 0000000..b55ce23
--- /dev/null
+++ b/libs/ui/GraphicLog.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <utils/Endian.h>
+#include <utils/Timers.h>
+
+#include <ui/GraphicLog.h>
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(GraphicLog)
+
+static inline
+void writeInt32(uint8_t* base, size_t& pos, int32_t value) {
+    int32_t v = htole32(value);
+    base[pos] = EVENT_TYPE_INT;
+    memcpy(&base[pos+1], &v, sizeof(int32_t));
+    pos += 1+sizeof(int32_t);
+}
+
+static inline
+void writeInt64(uint8_t* base,  size_t& pos, int64_t value) {
+    int64_t v = htole64(value);
+    base[pos] = EVENT_TYPE_LONG;
+    memcpy(&base[pos+1], &v, sizeof(int64_t));
+    pos += 1+sizeof(int64_t);
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t buffer)
+{
+    uint8_t scratch[2 + 2 + sizeof(int32_t) + sizeof(int64_t)];
+    size_t pos = 0;
+    scratch[pos++] = EVENT_TYPE_LIST;
+    scratch[pos++] = 2;
+    writeInt32(scratch, pos, buffer);
+    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+    android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t identity, int32_t buffer)
+{
+    uint8_t scratch[2 + 3 + sizeof(int32_t) + sizeof(int32_t) + sizeof(int64_t)];
+    size_t pos = 0;
+    scratch[pos++] = EVENT_TYPE_LIST;
+    scratch[pos++] = 3;
+    writeInt32(scratch, pos, buffer);
+    writeInt32(scratch, pos, identity);
+    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+    android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+GraphicLog::GraphicLog()
+    : mEnabled(0)
+{
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get("debug.graphic_log", property, NULL) > 0) {
+        mEnabled = atoi(property);
+    }
+}
+
+void GraphicLog::setEnabled(bool enable)
+{
+    mEnabled = enable;
+}
+
+}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b8a26b0..48dea57 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,7 +95,7 @@
     mFocusedApplication(NULL),
     mCurrentInputTargetsValid(false),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
-    mPollLoop = new PollLoop(false);
+    mLooper = new Looper(false);
 
     mInboundQueue.headSentinel.refCount = -1;
     mInboundQueue.headSentinel.type = EventEntry::TYPE_SENTINEL;
@@ -156,7 +156,7 @@
         timeoutMillis = 0;
     }
 
-    mPollLoop->pollOnce(timeoutMillis);
+    mLooper->pollOnce(timeoutMillis);
 }
 
 void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
@@ -1784,7 +1784,7 @@
     }
 }
 
-bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
     InputDispatcher* d = static_cast<InputDispatcher*>(data);
 
     { // acquire lock
@@ -1794,24 +1794,24 @@
         if (connectionIndex < 0) {
             LOGE("Received spurious receive callback for unknown input channel.  "
                     "fd=%d, events=0x%x", receiveFd, events);
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         nsecs_t currentTime = now();
 
         sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
-        if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+        if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
             LOGE("channel '%s' ~ Consumer closed input channel or an error occurred.  "
                     "events=0x%x", connection->getInputChannelName(), events);
             d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
-        if (! (events & POLLIN)) {
+        if (! (events & ALOOPER_EVENT_INPUT)) {
             LOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                     "events=0x%x", connection->getInputChannelName(), events);
-            return true;
+            return 1;
         }
 
         status_t status = connection->inputPublisher.receiveFinishedSignal();
@@ -1820,12 +1820,12 @@
                     connection->getInputChannelName(), status);
             d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
             d->runCommandsLockedInterruptible();
-            return false; // remove the callback
+            return 0; // remove the callback
         }
 
         d->finishDispatchCycleLocked(currentTime, connection);
         d->runCommandsLockedInterruptible();
-        return true;
+        return 1;
     } // release lock
 }
 
@@ -1843,7 +1843,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -1870,7 +1870,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -2007,7 +2007,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -2043,7 +2043,7 @@
     } // release lock
 
     if (needWake) {
-        mPollLoop->wake();
+        mLooper->wake();
     }
 
     int32_t injectionResult;
@@ -2294,7 +2294,7 @@
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
@@ -2317,7 +2317,7 @@
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
-    mPollLoop->wake();
+    mLooper->wake();
 }
 
 void InputDispatcher::releaseFocusedApplicationLocked() {
@@ -2355,7 +2355,7 @@
 
     if (changed) {
         // Wake up poll loop since it may need to make new input dispatching choices.
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -2372,7 +2372,7 @@
 
     if (preemptedOne) {
         // Wake up the poll loop so it can get a head start dispatching the next event.
-        mPollLoop->wake();
+        mLooper->wake();
     }
 }
 
@@ -2495,7 +2495,7 @@
             mMonitoringChannels.push(inputChannel);
         }
 
-        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+        mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
 
         runCommandsLockedInterruptible();
     } // release lock
@@ -2529,7 +2529,7 @@
             }
         }
 
-        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+        mLooper->removeFd(inputChannel->getReceivePipeFd());
 
         nsecs_t currentTime = now();
         abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
@@ -2539,7 +2539,7 @@
 
     // Wake the poll loop because removing the connection may have changed the current
     // synchronization state.
-    mPollLoop->wake();
+    mLooper->wake();
     return OK;
 }
 
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 2e20268..eb75ed8 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -86,7 +86,7 @@
 	$(commonSources) \
 	BackupData.cpp \
 	BackupHelpers.cpp \
-	PollLoop.cpp
+	Looper.cpp
 
 ifeq ($(TARGET_OS),linux)
 LOCAL_LDLIBS += -lrt -ldl
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
new file mode 100644
index 0000000..fd287da
--- /dev/null
+++ b/libs/utils/Looper.cpp
@@ -0,0 +1,368 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// A looper implementation based on epoll().
+//
+#define LOG_TAG "Looper"
+
+//#define LOG_NDEBUG 0
+
+// Debugs poll and wake interactions.
+#define DEBUG_POLL_AND_WAKE 0
+
+// Debugs callback registration and invocation.
+#define DEBUG_CALLBACKS 0
+
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+// Hint for number of file descriptors to be associated with the epoll instance.
+static const int EPOLL_SIZE_HINT = 8;
+
+// Maximum number of file descriptors for which to retrieve poll events each iteration.
+static const int EPOLL_MAX_EVENTS = 16;
+
+Looper::Looper(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks),
+        mResponseIndex(0) {
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
+
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
+
+    mWakeReadPipeFd = wakeFds[0];
+    mWakeWritePipeFd = wakeFds[1];
+
+    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
+            errno);
+
+    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
+            errno);
+
+    struct epoll_event eventItem;
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeReadPipeFd;
+    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
+            errno);
+}
+
+Looper::~Looper() {
+    close(mWakeReadPipeFd);
+    close(mWakeWritePipeFd);
+    close(mEpollFd);
+}
+
+void Looper::threadDestructor(void *st) {
+    Looper* const self = static_cast<Looper*>(st);
+    if (self != NULL) {
+        self->decStrong((void*)threadDestructor);
+    }
+}
+
+void Looper::setForThread(const sp<Looper>& looper) {
+    sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
+
+    if (looper != NULL) {
+        looper->incStrong((void*)threadDestructor);
+    }
+
+    pthread_setspecific(gTLS, looper.get());
+
+    if (old != NULL) {
+        old->decStrong((void*)threadDestructor);
+    }
+}
+
+sp<Looper> Looper::getForThread() {
+    if (!gHaveTLS) {
+        pthread_mutex_lock(&gTLSMutex);
+        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+            pthread_mutex_unlock(&gTLSMutex);
+            return NULL;
+        }
+        gHaveTLS = true;
+        pthread_mutex_unlock(&gTLSMutex);
+    }
+
+    return (Looper*)pthread_getspecific(gTLS);
+}
+
+sp<Looper> Looper::prepare(int opts) {
+    bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        looper = new Looper(allowNonCallbacks);
+        Looper::setForThread(looper);
+    }
+    if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
+        LOGW("Looper already prepared for this thread with a different value for the "
+                "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
+    }
+    return looper;
+}
+
+bool Looper::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
+int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    int result = 0;
+    for (;;) {
+        while (mResponseIndex < mResponses.size()) {
+            const Response& response = mResponses.itemAt(mResponseIndex++);
+            if (! response.request.callback) {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - returning signalled identifier %d: "
+                        "fd=%d, events=0x%x, data=%p", this,
+                        response.request.ident, response.request.fd,
+                        response.events, response.request.data);
+#endif
+                if (outFd != NULL) *outFd = response.request.fd;
+                if (outEvents != NULL) *outEvents = response.events;
+                if (outData != NULL) *outData = response.request.data;
+                return response.request.ident;
+            }
+        }
+
+        if (result != 0) {
+#if DEBUG_POLL_AND_WAKE
+            LOGD("%p ~ pollOnce - returning result %d", this, result);
+#endif
+            if (outFd != NULL) *outFd = 0;
+            if (outEvents != NULL) *outEvents = NULL;
+            if (outData != NULL) *outData = NULL;
+            return result;
+        }
+
+        result = pollInner(timeoutMillis);
+    }
+}
+
+int Looper::pollInner(int timeoutMillis) {
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
+#endif
+    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
+    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+    if (eventCount < 0) {
+        if (errno != EINTR) {
+            LOGW("Poll failed with an unexpected error, errno=%d", errno);
+        }
+        return ALOOPER_POLL_ERROR;
+    }
+
+    if (eventCount == 0) {
+#if DEBUG_POLL_AND_WAKE
+        LOGD("%p ~ pollOnce - timeout", this);
+#endif
+        return ALOOPER_POLL_TIMEOUT;
+    }
+
+    int result = ALOOPER_POLL_WAKE;
+    mResponses.clear();
+    mResponseIndex = 0;
+
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
+#endif
+    { // acquire lock
+        AutoMutex _l(mLock);
+        for (int i = 0; i < eventCount; i++) {
+            int fd = eventItems[i].data.fd;
+            uint32_t epollEvents = eventItems[i].events;
+            if (fd == mWakeReadPipeFd) {
+                if (epollEvents & EPOLLIN) {
+#if DEBUG_POLL_AND_WAKE
+                    LOGD("%p ~ pollOnce - awoken", this);
+#endif
+                    char buffer[16];
+                    ssize_t nRead;
+                    do {
+                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+                    } while (nRead == sizeof(buffer));
+                } else {
+                    LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+                }
+            } else {
+                ssize_t requestIndex = mRequests.indexOfKey(fd);
+                if (requestIndex >= 0) {
+                    int events = 0;
+                    if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
+                    if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+                    if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
+                    if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
+
+                    Response response;
+                    response.events = events;
+                    response.request = mRequests.valueAt(requestIndex);
+                    mResponses.push(response);
+                } else {
+                    LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
+                            "no longer registered.", epollEvents, fd);
+                }
+            }
+        }
+    }
+
+    for (size_t i = 0; i < mResponses.size(); i++) {
+        const Response& response = mResponses.itemAt(i);
+        if (response.request.callback) {
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+            LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
+                    response.request.fd, response.events, response.request.data);
+#endif
+            int callbackResult = response.request.callback(
+                    response.request.fd, response.events, response.request.data);
+            if (callbackResult == 0) {
+                removeFd(response.request.fd);
+            }
+
+            result = ALOOPER_POLL_CALLBACK;
+        }
+    }
+    return result;
+}
+
+int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    if (timeoutMillis <= 0) {
+        int result;
+        do {
+            result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+        } while (result == ALOOPER_POLL_CALLBACK);
+        return result;
+    } else {
+        nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
+                + milliseconds_to_nanoseconds(timeoutMillis);
+
+        for (;;) {
+            int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+            if (result != ALOOPER_POLL_CALLBACK) {
+                return result;
+            }
+
+            nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
+            if (timeoutNanos <= 0) {
+                return ALOOPER_POLL_TIMEOUT;
+            }
+
+            timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
+        }
+    }
+}
+
+void Looper::wake() {
+#if DEBUG_POLL_AND_WAKE
+    LOGD("%p ~ wake", this);
+#endif
+
+    ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
+    if (nWrite != 1) {
+        if (errno != EAGAIN) {
+            LOGW("Could not write wake signal, errno=%d", errno);
+        }
+    }
+}
+
+int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
+            events, callback, data);
+#endif
+
+    int epollEvents = 0;
+    if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+    if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
+    if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
+
+    if (epollEvents == 0) {
+        LOGE("Invalid attempt to set a callback with no selected poll events.");
+        return -1;
+    }
+
+    if (! callback) {
+        if (! mAllowNonCallbacks) {
+            LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
+            return -1;
+        }
+
+        if (ident < 0) {
+            LOGE("Invalid attempt to set NULL callback with ident <= 0.");
+            return -1;
+        }
+    }
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        Request request;
+        request.fd = fd;
+        request.ident = ident;
+        request.callback = callback;
+        request.data = data;
+
+        struct epoll_event eventItem;
+        eventItem.events = epollEvents;
+        eventItem.data.fd = fd;
+
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+            if (epollResult < 0) {
+                LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.add(fd, request);
+        } else {
+            int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+            if (epollResult < 0) {
+                LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
+                return -1;
+            }
+            mRequests.replaceValueAt(requestIndex, request);
+        }
+    } // release lock
+    return 1;
+}
+
+int Looper::removeFd(int fd) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ removeFd - fd=%d", this, fd);
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+        ssize_t requestIndex = mRequests.indexOfKey(fd);
+        if (requestIndex < 0) {
+            return 0;
+        }
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        if (epollResult < 0) {
+            LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
+            return -1;
+        }
+
+        mRequests.removeItemsAt(requestIndex);
+    } // request lock
+    return 1;
+}
+
+} // namespace android
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
deleted file mode 100644
index fe76cd0..0000000
--- a/libs/utils/PollLoop.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// A select loop implementation.
-//
-#define LOG_TAG "PollLoop"
-
-//#define LOG_NDEBUG 0
-
-// Debugs poll and wake interactions.
-#define DEBUG_POLL_AND_WAKE 0
-
-// Debugs callback registration and invocation.
-#define DEBUG_CALLBACKS 0
-
-#include <cutils/log.h>
-#include <utils/PollLoop.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-namespace android {
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-
-PollLoop::PollLoop(bool allowNonCallbacks) :
-        mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
-        mWaiters(0), mPendingFdsPos(0) {
-    openWakePipe();
-}
-
-PollLoop::~PollLoop() {
-    closeWakePipe();
-}
-
-void PollLoop::threadDestructor(void *st) {
-    PollLoop* const self = static_cast<PollLoop*>(st);
-    if (self != NULL) {
-        self->decStrong((void*)threadDestructor);
-    }
-}
-
-void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
-    sp<PollLoop> old = getForThread();
-    
-    if (pollLoop != NULL) {
-        pollLoop->incStrong((void*)threadDestructor);
-    }
-    
-    pthread_setspecific(gTLS, pollLoop.get());
-    
-    if (old != NULL) {
-        old->decStrong((void*)threadDestructor);
-    }
-}
-    
-sp<PollLoop> PollLoop::getForThread() {
-    if (!gHaveTLS) {
-        pthread_mutex_lock(&gTLSMutex);
-        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
-            pthread_mutex_unlock(&gTLSMutex);
-            return NULL;
-        }
-        gHaveTLS = true;
-        pthread_mutex_unlock(&gTLSMutex);
-    }
-    
-    return (PollLoop*)pthread_getspecific(gTLS);
-}
-
-void PollLoop::openWakePipe() {
-    int wakeFds[2];
-    int result = pipe(wakeFds);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
-
-    mWakeReadPipeFd = wakeFds[0];
-    mWakeWritePipeFd = wakeFds[1];
-
-    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
-            errno);
-
-    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
-            errno);
-
-    // Add the wake pipe to the head of the request list with a null callback.
-    struct pollfd requestedFd;
-    requestedFd.fd = mWakeReadPipeFd;
-    requestedFd.events = POLLIN;
-    mRequestedFds.insertAt(requestedFd, 0);
-
-    RequestedCallback requestedCallback;
-    requestedCallback.callback = NULL;
-    requestedCallback.looperCallback = NULL;
-    requestedCallback.ident = 0;
-    requestedCallback.data = NULL;
-    mRequestedCallbacks.insertAt(requestedCallback, 0);
-}
-
-void PollLoop::closeWakePipe() {
-    close(mWakeReadPipeFd);
-    close(mWakeWritePipeFd);
-
-    // Note: We don't need to remove the poll structure or callback entry because this
-    //       method is currently only called by the destructor.
-}
-
-int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
-    // If there are still pending fds from the last call, dispatch those
-    // first, to avoid an earlier fd from starving later ones.
-    const size_t pendingFdsCount = mPendingFds.size();
-    if (mPendingFdsPos < pendingFdsCount) {
-        const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
-        mPendingFdsPos++;
-        if (outEvents != NULL) *outEvents = pending.events;
-        if (outData != NULL) *outData = pending.data;
-        return pending.ident;
-    }
-
-    // Wait for wakeAndLock() waiters to run then set mPolling to true.
-    mLock.lock();
-    while (mWaiters != 0) {
-        mResume.wait(mLock);
-    }
-    mPolling = true;
-    mLock.unlock();
-
-    // Poll.
-    int32_t result;
-    size_t requestedCount = mRequestedFds.size();
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
-    for (size_t i = 0; i < requestedCount; i++) {
-        LOGD("  fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
-    }
-#endif
-
-    int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
-
-    if (respondedCount == 0) {
-        // Timeout
-#if DEBUG_POLL_AND_WAKE
-        LOGD("%p ~ pollOnce - timeout", this);
-#endif
-        result = POLL_TIMEOUT;
-        goto Done;
-    }
-
-    if (respondedCount < 0) {
-        // Error
-#if DEBUG_POLL_AND_WAKE
-        LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
-#endif
-        if (errno != EINTR) {
-            LOGW("Poll failed with an unexpected error, errno=%d", errno);
-        }
-        result = POLL_ERROR;
-        goto Done;
-    }
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
-    for (size_t i = 0; i < requestedCount; i++) {
-        LOGD("  fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
-                mRequestedFds[i].revents);
-    }
-#endif
-
-    // Process the poll results.
-    mPendingCallbacks.clear();
-    mPendingFds.clear();
-    mPendingFdsPos = 0;
-    if (outEvents != NULL) *outEvents = 0;
-    if (outData != NULL) *outData = NULL;
-    
-    result = POLL_CALLBACK;
-    for (size_t i = 0; i < requestedCount; i++) {
-        const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
-
-        short revents = requestedFd.revents;
-        if (revents) {
-            const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
-            PendingCallback pending;
-            pending.fd = requestedFd.fd;
-            pending.ident = requestedCallback.ident;
-            pending.events = revents;
-            pending.callback = requestedCallback.callback;
-            pending.looperCallback = requestedCallback.looperCallback;
-            pending.data = requestedCallback.data;
-
-            if (pending.callback || pending.looperCallback) {
-                mPendingCallbacks.push(pending);
-            } else if (pending.fd != mWakeReadPipeFd) {
-                if (result == POLL_CALLBACK) {
-                    result = pending.ident;
-                    if (outEvents != NULL) *outEvents = pending.events;
-                    if (outData != NULL) *outData = pending.data;
-                } else {
-                    mPendingFds.push(pending);
-                }
-            } else {
-#if DEBUG_POLL_AND_WAKE
-                LOGD("%p ~ pollOnce - awoken", this);
-#endif
-                char buffer[16];
-                ssize_t nRead;
-                do {
-                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                } while (nRead == sizeof(buffer));
-            }
-
-            respondedCount -= 1;
-            if (respondedCount == 0) {
-                break;
-            }
-        }
-    }
-
-Done:
-    // Set mPolling to false and wake up the wakeAndLock() waiters.
-    mLock.lock();
-    mPolling = false;
-    if (mWaiters != 0) {
-        mAwake.broadcast();
-    }
-    mLock.unlock();
-
-    if (result == POLL_CALLBACK || result >= 0) {
-        size_t pendingCount = mPendingCallbacks.size();
-        for (size_t i = 0; i < pendingCount; i++) {
-            const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-            LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
-#endif
-
-            bool keep = true;
-            if (pendingCallback.callback != NULL) {
-                keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
-                        pendingCallback.data);
-            } else {
-                keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
-                        pendingCallback.data) != 0;
-            }
-            if (! keep) {
-                removeCallback(pendingCallback.fd);
-            }
-        }
-    }
-
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ pollOnce - done", this);
-#endif
-    return result;
-}
-
-void PollLoop::wake() {
-#if DEBUG_POLL_AND_WAKE
-    LOGD("%p ~ wake", this);
-#endif
-
-    ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
-    if (nWrite != 1) {
-        if (errno != EAGAIN) {
-            LOGW("Could not write wake signal, errno=%d", errno);
-        }
-    }
-}
-
-bool PollLoop::getAllowNonCallbacks() const {
-    return mAllowNonCallbacks;
-}
-
-void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
-    setCallbackCommon(fd, ident, events, callback, NULL, data);
-}
-
-void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
-    setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
-}
-
-void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
-        void* data) {
-    setCallbackCommon(fd, ident, events, NULL, callback, data);
-}
-
-void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
-        ALooper_callbackFunc* looperCallback, void* data) {
-
-#if DEBUG_CALLBACKS
-    LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
-#endif
-
-    if (! events) {
-        LOGE("Invalid attempt to set a callback with no selected poll events.");
-        removeCallback(fd);
-        return;
-    }
-
-    if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
-        LOGE("Invalid attempt to set NULL callback but not allowed.");
-        removeCallback(fd);
-        return;
-    }
-    
-    wakeAndLock();
-
-    struct pollfd requestedFd;
-    requestedFd.fd = fd;
-    requestedFd.events = events;
-
-    RequestedCallback requestedCallback;
-    requestedCallback.callback = callback;
-    requestedCallback.looperCallback = looperCallback;
-    requestedCallback.ident = ident;
-    requestedCallback.data = data;
-
-    ssize_t index = getRequestIndexLocked(fd);
-    if (index < 0) {
-        mRequestedFds.push(requestedFd);
-        mRequestedCallbacks.push(requestedCallback);
-    } else {
-        mRequestedFds.replaceAt(requestedFd, size_t(index));
-        mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
-    }
-
-    mLock.unlock();
-}
-
-bool PollLoop::removeCallback(int fd) {
-#if DEBUG_CALLBACKS
-    LOGD("%p ~ removeCallback - fd=%d", this, fd);
-#endif
-
-    wakeAndLock();
-
-    ssize_t index = getRequestIndexLocked(fd);
-    if (index >= 0) {
-        mRequestedFds.removeAt(size_t(index));
-        mRequestedCallbacks.removeAt(size_t(index));
-    }
-
-    mLock.unlock();
-    return index >= 0;
-}
-
-ssize_t PollLoop::getRequestIndexLocked(int fd) {
-    size_t requestCount = mRequestedFds.size();
-
-    for (size_t i = 0; i < requestCount; i++) {
-        if (mRequestedFds.itemAt(i).fd == fd) {
-            return i;
-        }
-    }
-
-    return -1;
-}
-
-void PollLoop::wakeAndLock() {
-    mLock.lock();
-
-    mWaiters += 1;
-    while (mPolling) {
-        wake();
-        mAwake.wait(mLock);
-    }
-
-    mWaiters -= 1;
-    if (mWaiters == 0) {
-        mResume.signal();
-    }
-}
-
-} // namespace android
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 725de9c..00077ee 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -7,7 +7,7 @@
 # Build the unit tests.
 test_src_files := \
 	ObbFile_test.cpp \
-	PollLoop_test.cpp \
+	Looper_test.cpp \
 	String8_test.cpp
 
 shared_libraries := \
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
new file mode 100644
index 0000000..afc92f8
--- /dev/null
+++ b/libs/utils/tests/Looper_test.cpp
@@ -0,0 +1,433 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/StopWatch.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "TestHelpers.h"
+
+// # of milliseconds to fudge stopwatch measurements
+#define TIMING_TOLERANCE_MS 25
+
+namespace android {
+
+class DelayedWake : public DelayedTask {
+    sp<Looper> mLooper;
+
+public:
+    DelayedWake(int delayMillis, const sp<Looper> looper) :
+        DelayedTask(delayMillis), mLooper(looper) {
+    }
+
+protected:
+    virtual void doTask() {
+        mLooper->wake();
+    }
+};
+
+class DelayedWriteSignal : public DelayedTask {
+    Pipe* mPipe;
+
+public:
+    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
+        DelayedTask(delayMillis), mPipe(pipe) {
+    }
+
+protected:
+    virtual void doTask() {
+        mPipe->writeSignal();
+    }
+};
+
+class CallbackHandler {
+public:
+    void setCallback(const sp<Looper>& looper, int fd, int events) {
+        looper->addFd(fd, 0, events, staticHandler, this);
+    }
+
+protected:
+    virtual ~CallbackHandler() { }
+
+    virtual int handler(int fd, int events) = 0;
+
+private:
+    static int staticHandler(int fd, int events, void* data) {
+        return static_cast<CallbackHandler*>(data)->handler(fd, events);
+    }
+};
+
+class StubCallbackHandler : public CallbackHandler {
+public:
+    int nextResult;
+    int callbackCount;
+
+    int fd;
+    int events;
+
+    StubCallbackHandler(int nextResult) : nextResult(nextResult),
+            callbackCount(0), fd(-1), events(-1) {
+    }
+
+protected:
+    virtual int handler(int fd, int events) {
+        callbackCount += 1;
+        this->fd = fd;
+        this->events = events;
+        return nextResult;
+    }
+};
+
+class LooperTest : public testing::Test {
+protected:
+    sp<Looper> mLooper;
+
+    virtual void SetUp() {
+        mLooper = new Looper(true);
+    }
+
+    virtual void TearDown() {
+        mLooper.clear();
+    }
+};
+
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
+    mLooper->wake();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because wake() was called before waiting";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
+    sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
+    delayedWake->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal wake delay";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    ASSERT_EQ(OK, pipe.writeSignal());
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    pipe.writeSignal();
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    delayedWriteSignal->run();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal signal delay";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked exactly once";
+    EXPECT_EQ(pipe.receiveFd, handler.fd)
+            << "callback should have received pipe fd as parameter";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+            << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler(true);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    pipe.writeSignal(); // would cause FD to be considered signalled
+    mLooper->removeFd(pipe.receiveFd);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal timeout because FD was no longer registered";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(0, handler.callbackCount)
+            << "callback should not be invoked";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First loop: Callback is registered and FD is signalled.
+    pipe.writeSignal();
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should be invoked";
+
+    // Second loop: Callback is no longer registered and FD is signalled.
+    pipe.writeSignal();
+
+    stopWatch.reset();
+    result = mLooper->pollOnce(0);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. equal zero because timeout was zero";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+    EXPECT_EQ(1, handler.callbackCount)
+            << "callback should not be invoked this time";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
+    const int expectedIdent = 5;
+    void* expectedData = this;
+
+    Pipe pipe;
+
+    pipe.writeSignal();
+    mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
+
+    StopWatch stopWatch("pollOnce");
+    int fd;
+    int events;
+    void* data;
+    int result = mLooper->pollOnce(100, &fd, &events, &data);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should be approx. zero";
+    EXPECT_EQ(expectedIdent, result)
+            << "pollOnce result should be the ident of the FD that was signalled";
+    EXPECT_EQ(pipe.receiveFd, fd)
+            << "pollOnce should have returned the received pipe fd";
+    EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
+            << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
+    EXPECT_EQ(expectedData, data)
+            << "pollOnce should have returned the data";
+}
+
+TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(1, result)
+            << "addFd should return 1 because FD was added";
+}
+
+TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
+    Pipe pipe;
+    int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
+    Pipe pipe;
+    sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
+    int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+    EXPECT_EQ(-1, result)
+            << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
+    int result = mLooper->removeFd(1);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 because FD not registered";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
+    Pipe pipe;
+    StubCallbackHandler handler(false);
+    handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+    // First time.
+    int result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(1, result)
+            << "removeFd should return 1 first time because FD was registered";
+
+    // Second time.
+    result = mLooper->removeFd(pipe.receiveFd);
+
+    EXPECT_EQ(0, result)
+            << "removeFd should return 0 second time because FD was no longer registered";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
+    Pipe pipe;
+    StubCallbackHandler handler1(true);
+    StubCallbackHandler handler2(true);
+
+    handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+    handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
+    pipe.writeSignal(); // would cause FD to be considered signalled
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    ASSERT_EQ(OK, pipe.readSignal())
+            << "signal should actually have been written";
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because FD was already signalled";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+    EXPECT_EQ(0, handler1.callbackCount)
+            << "original handler callback should not be invoked because it was replaced";
+    EXPECT_EQ(1, handler2.callbackCount)
+            << "replacement handler callback should be invoked";
+}
+
+
+} // namespace android
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
deleted file mode 100644
index 02f1808..0000000
--- a/libs/utils/tests/PollLoop_test.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-
-#include <utils/PollLoop.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-
-#include "TestHelpers.h"
-
-// # of milliseconds to fudge stopwatch measurements
-#define TIMING_TOLERANCE_MS 25
-
-namespace android {
-
-class DelayedWake : public DelayedTask {
-    sp<PollLoop> mPollLoop;
-
-public:
-    DelayedWake(int delayMillis, const sp<PollLoop> pollLoop) :
-        DelayedTask(delayMillis), mPollLoop(pollLoop) {
-    }
-
-protected:
-    virtual void doTask() {
-        mPollLoop->wake();
-    }
-};
-
-class DelayedWriteSignal : public DelayedTask {
-    Pipe* mPipe;
-
-public:
-    DelayedWriteSignal(int delayMillis, Pipe* pipe) :
-        DelayedTask(delayMillis), mPipe(pipe) {
-    }
-
-protected:
-    virtual void doTask() {
-        mPipe->writeSignal();
-    }
-};
-
-class CallbackHandler {
-public:
-    void setCallback(const sp<PollLoop>& pollLoop, int fd, int events) {
-        pollLoop->setCallback(fd, events, staticHandler, this);
-    }
-
-protected:
-    virtual ~CallbackHandler() { }
-
-    virtual bool handler(int fd, int events) = 0;
-
-private:
-    static bool staticHandler(int fd, int events, void* data) {
-        return static_cast<CallbackHandler*>(data)->handler(fd, events);
-    }
-};
-
-class StubCallbackHandler : public CallbackHandler {
-public:
-    bool nextResult;
-    int callbackCount;
-
-    int fd;
-    int events;
-
-    StubCallbackHandler(bool nextResult) : nextResult(nextResult),
-            callbackCount(0), fd(-1), events(-1) {
-    }
-
-protected:
-    virtual bool handler(int fd, int events) {
-        callbackCount += 1;
-        this->fd = fd;
-        this->events = events;
-        return nextResult;
-    }
-};
-
-class PollLoopTest : public testing::Test {
-protected:
-    sp<PollLoop> mPollLoop;
-
-    virtual void SetUp() {
-        mPollLoop = new PollLoop(false);
-    }
-
-    virtual void TearDown() {
-        mPollLoop.clear();
-    }
-};
-
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
-    mPollLoop->wake();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. zero because wake() was called before waiting";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
-    sp<DelayedWake> delayedWake = new DelayedWake(100, mPollLoop);
-    delayedWake->run();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal wake delay";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    ASSERT_EQ(OK, pipe.writeSignal());
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturnsFalse) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    pipe.writeSignal();
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should be approx. zero";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturnsTrue) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-    sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    delayedWriteSignal->run();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(1000);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal signal delay";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked exactly once";
-    EXPECT_EQ(pipe.receiveFd, handler.fd)
-            << "callback should have received pipe fd as parameter";
-    EXPECT_EQ(POLL_IN, handler.events)
-            << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
-    Pipe pipe;
-    StubCallbackHandler handler(true);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    pipe.writeSignal(); // would cause FD to be considered signalled
-    mPollLoop->removeCallback(pipe.receiveFd);
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal timeout because FD was no longer registered";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(0, handler.callbackCount)
-            << "callback should not be invoked";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
-    Pipe pipe;
-    StubCallbackHandler handler(false);
-
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    // First loop: Callback is registered and FD is signalled.
-    pipe.writeSignal();
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(0);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal zero because FD was already signalled";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should be invoked";
-
-    // Second loop: Callback is no longer registered and FD is signalled.
-    pipe.writeSignal();
-
-    stopWatch.reset();
-    result = mPollLoop->pollOnce(0);
-    elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. equal zero because timeout was zero";
-    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
-            << "pollOnce result should be POLL_TIMEOUT";
-    EXPECT_EQ(1, handler.callbackCount)
-            << "callback should not be invoked this time";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackNotAdded_ReturnsFalse) {
-    bool result = mPollLoop->removeCallback(1);
-
-    EXPECT_FALSE(result)
-            << "removeCallback should return false because FD not registered";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackAddedThenRemovedTwice_ReturnsTrueFirstTimeAndReturnsFalseSecondTime) {
-    Pipe pipe;
-    StubCallbackHandler handler(false);
-    handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
-    // First time.
-    bool result = mPollLoop->removeCallback(pipe.receiveFd);
-
-    EXPECT_TRUE(result)
-            << "removeCallback should return true first time because FD was registered";
-
-    // Second time.
-    result = mPollLoop->removeCallback(pipe.receiveFd);
-
-    EXPECT_FALSE(result)
-            << "removeCallback should return false second time because FD was no longer registered";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
-    Pipe pipe;
-    StubCallbackHandler handler1(true);
-    StubCallbackHandler handler2(true);
-
-    handler1.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-    handler2.setCallback(mPollLoop, pipe.receiveFd, POLL_IN); // replace it
-    pipe.writeSignal(); // would cause FD to be considered signalled
-
-    StopWatch stopWatch("pollOnce");
-    int32_t result = mPollLoop->pollOnce(100);
-    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
-    ASSERT_EQ(OK, pipe.readSignal())
-            << "signal should actually have been written";
-    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
-            << "elapsed time should approx. zero because FD was already signalled";
-    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
-            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
-    EXPECT_EQ(0, handler1.callbackCount)
-            << "original handler callback should not be invoked because it was replaced";
-    EXPECT_EQ(1, handler2.callbackCount)
-            << "replacement handler callback should be invoked";
-}
-
-
-} // namespace android
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index 35038fa..ae67114 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -16,12 +16,14 @@
 
 package android.media;
 
-import android.util.Log;
-import java.lang.ref.WeakReference;
-import java.io.IOException;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
 import java.util.UUID;
@@ -839,6 +841,128 @@
                 byte[] value);
     }
 
+
+    // -------------------------------------------------------------------------
+    // Audio Effect Control panel intents
+    // -------------------------------------------------------------------------
+
+    /**
+     *  This intent launches an audio effect control panel UI. The goal of this intent is to enable
+     *  separate implementations of music/media player applications and audio effect control
+     *  application or services. This will allow platform vendors to offer more advanced control
+     *  options for standard effects or control for platform specific effects.
+     *  <p>The intent carries a number of extras used by the player application to communicate
+     *  necessary pieces of information to the control panel application.
+     *  <p>The calling application must use the
+     *  {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the
+     *  control panel so that its package name is indicated and used by the control panel
+     *  application to keep track of changes for this particular application.
+     *  <p>The android.media.EXTRA_AUDIO_SESSION extra will indicate an audio session to which the
+     *  audio effects should be applied. If no audio session is specified, either one of the
+     *  follownig will happen:
+     *  - If an audio session was previously opened by the calling application with
+     *  {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will
+     *  be applied to that session.
+     *  - If no audio session is opened, the changes will be stored in the package specific storage
+     *  area and applied whenever a new audio session is opened by this application.
+     *  <p>The android.media.EXTRA_CONTENT_TYPE extra will help the control panel application
+     *  customize both the UI layout and the default audio effect settings if none are already
+     *  stored for the calling application.
+     *  {@hide} pending API council approval
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL =
+        "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
+
+    /**
+     *  This intent indicates to the effect control application or service that a new audio session
+     *  is opened and requires audio effects to be applied. This is different from
+     *  {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no UI should be displayed in
+     *  this case. Music player applications can broadcast this intent before starting playback
+     *  to make sure that any audio effect settings previously selected by the user are applied.
+     *  <p>The effect control application receiving this intent will look for previously stored
+     *  settings for the calling application, create all required audio effects and apply the
+     *  effect settings to the specified audio session.
+     *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+     *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+     *  <p>If no stored settings are found for the calling application, default settings for the
+     *  content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings
+     *  for a given content type are platform specific.
+     *  {@hide} pending API council approval
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION =
+        "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
+
+    /**
+     *  This intent indicates to the effect control application or service that an audio session
+     *  is closed and that effects should not be applied anymore.
+     *  <p>The effect control application receiving this intent will delete all effects on this
+     *  session and store current settings in package specific storage.
+     *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+     *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+     *  <p>It is good practice for applications to broadcast this intent when music playback stops
+     *  and/or when exiting to free system resources consumed by audio effect engines.
+     *  {@hide} pending API council approval
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION =
+        "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
+
+    /**
+     * This extra indicates the ID of the audio session the effects should be applied to.
+     * <p>The extra value is of type int and is the audio session ID.
+     *  @see android.media.MediaPlayer#setAudioSessionId(int) for details on audio sessions.
+     *  {@hide} pending API council approval
+     */
+     public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
+
+    /**
+     * This extra indicates the package name of the calling application for
+     * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+     * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
+     * <p>The extra value is a string containing the full package name.
+     *  {@hide} pending API council approval
+     */
+    public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
+
+    /**
+     * This extra indicates which type of content is played by the application. This information is
+     * used by the effect control application to customize UI and default effect settings.
+     * The content type is one of the following:
+     * <ul>
+     *   <li>{@link #CONTENT_TYPE_MUSIC}</li>
+     *   <li>{@link #CONTENT_TYPE_MOVIE}</li>
+     *   <li>{@link #CONTENT_TYPE_GAME}</li>
+     *   <li>{@link #CONTENT_TYPE_VOICE}</li>
+     * </ul>
+     * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}.
+     *  {@hide} pending API council approval
+     */
+    public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
+
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music
+     *  {@hide} pending API council approval
+     */
+    public static final int  CONTENT_TYPE_MUSIC = 0;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video of movie
+     *  {@hide} pending API council approval
+     */
+    public static final int  CONTENT_TYPE_MOVIE = 1;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio
+     *  {@hide} pending API council approval
+     */
+    public static final int  CONTENT_TYPE_GAME = 2;
+    /**
+     * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio
+     *  {@hide} pending API council approval
+     */
+    public static final int  CONTENT_TYPE_VOICE = 3;
+
+
     // ---------------------------------------------------------
     // Inner classes
     // --------------------
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b8403e1..280def9 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1210,7 +1210,6 @@
      * effect which can be applied on any sound source that directs a certain amount of its
      * energy to this effect. This amount is defined by setAuxEffectSendLevel().
      * {@see #setAuxEffectSendLevel(float)}.
-     // TODO when AudioEffect is unhidden
      * <p>After creating an auxiliary effect (e.g. {@link android.media.EnvironmentalReverb}),
      * retrieve its ID with {@link android.media.AudioEffect#getId()} and use it when calling
      * this method to attach the player to the effect.
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 57f0072..c753aa5 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -20,7 +20,7 @@
 #include <android/input.h>
 #include <ui/Input.h>
 #include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
@@ -250,7 +250,7 @@
 
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        int ident, ALooper_callbackFunc* callback, void* data) {
+        int ident, ALooper_callbackFunc callback, void* data) {
     queue->attachLooper(looper, ident, callback, data);
 }
 
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 0aeed77..9f5cda9 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -18,65 +18,56 @@
 #include <utils/Log.h>
 
 #include <android/looper.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
-using android::PollLoop;
+using android::Looper;
 using android::sp;
 
 ALooper* ALooper_forThread() {
-    return PollLoop::getForThread().get();
+    return Looper::getForThread().get();
 }
 
-ALooper* ALooper_prepare(int32_t opts) {
-    bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        loop = new PollLoop(allowFds);
-        PollLoop::setForThread(loop);
-    }
-    if (loop->getAllowNonCallbacks() != allowFds) {
-        LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
-    }
-    return loop.get();
-}
-
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        LOGW("ALooper_pollOnce: No looper for this thread!");
-        return -1;
-    }
-    return loop->pollOnce(timeoutMillis, outEvents, outData);
-}
-
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
-    sp<PollLoop> loop = PollLoop::getForThread();
-    if (loop == NULL) {
-        LOGW("ALooper_pollOnce: No looper for this thread!");
-        return -1;
-    }
-    
-    int32_t result;
-    while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
-        ;
-    }
-    
-    return result;
+ALooper* ALooper_prepare(int opts) {
+    return Looper::prepare(opts).get();
 }
 
 void ALooper_acquire(ALooper* looper) {
-    static_cast<PollLoop*>(looper)->incStrong((void*)ALooper_acquire);
+    static_cast<Looper*>(looper)->incStrong((void*)ALooper_acquire);
 }
 
 void ALooper_release(ALooper* looper) {
-    static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
+    static_cast<Looper*>(looper)->decStrong((void*)ALooper_acquire);
 }
 
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
-        ALooper_callbackFunc* callback, void* data) {
-    static_cast<PollLoop*>(looper)->setLooperCallback(fd, ident, events, callback, data);
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        LOGE("ALooper_pollOnce: No looper for this thread!");
+        return ALOOPER_POLL_ERROR;
+    }
+
+    return looper->pollOnce(timeoutMillis, outFd, outEvents, outData);
 }
 
-int32_t ALooper_removeFd(ALooper* looper, int fd) {
-    return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+    sp<Looper> looper = Looper::getForThread();
+    if (looper == NULL) {
+        LOGE("ALooper_pollAll: No looper for this thread!");
+        return ALOOPER_POLL_ERROR;
+    }
+    
+    return looper->pollAll(timeoutMillis, outFd, outEvents, outData);
+}
+
+void ALooper_wake(ALooper* looper) {
+    static_cast<Looper*>(looper)->wake();
+}
+
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+        ALooper_callbackFunc callback, void* data) {
+    return static_cast<Looper*>(looper)->addFd(fd, ident, events, callback, data);
+}
+
+int ALooper_removeFd(ALooper* looper, int fd) {
+    return static_cast<Looper*>(looper)->removeFd(fd);
 }
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index cf7635d..76c6eda 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -21,7 +21,7 @@
 #include <android/sensor.h>
 
 #include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 #include <utils/Timers.h>
 
 #include <gui/Sensor.h>
@@ -60,12 +60,12 @@
 }
 
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data)
+        ALooper* looper, int ident, ALooper_callbackFunc callback, void* data)
 {
     sp<SensorEventQueue> queue =
             static_cast<SensorManager*>(manager)->createEventQueue();
     if (queue != 0) {
-        ALooper_addFd(looper, queue->getFd(), ident, POLLIN, callback, data);
+        ALooper_addFd(looper, queue->getFd(), ident, ALOOPER_EVENT_INPUT, callback, data);
         queue->looper = looper;
         queue->incStrong(manager);
     }
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 9da122b..c1134bf 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -645,7 +645,7 @@
  * ALooper_addFd() for information on the ident, callback, and data params.
  */
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        int ident, ALooper_callbackFunc* callback, void* data);
+        int ident, ALooper_callbackFunc callback, void* data);
 
 /*
  * Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 287bcd5..a63b744 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -18,8 +18,6 @@
 #ifndef ANDROID_LOOPER_H
 #define ANDROID_LOOPER_H
 
-#include <poll.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,25 +39,14 @@
 typedef struct ALooper ALooper;
 
 /**
- * For callback-based event loops, this is the prototype of the function
- * that is called.  It is given the file descriptor it is associated with,
- * a bitmask of the poll events that were triggered (typically POLLIN), and
- * the data pointer that was originally supplied.
- *
- * Implementations should return 1 to continue receiving callbacks, or 0
- * to have this file descriptor and callback unregistered from the looper.
- */
-typedef int ALooper_callbackFunc(int fd, int events, void* data);
-
-/**
- * Return the ALooper associated with the calling thread, or NULL if
+ * Returns the looper associated with the calling thread, or NULL if
  * there is not one.
  */
 ALooper* ALooper_forThread();
 
 enum {
     /**
-     * Option for ALooper_prepare: this ALooper will accept calls to
+     * Option for ALooper_prepare: this looper will accept calls to
      * ALooper_addFd() that do not have a callback (that is provide NULL
      * for the callback).  In this case the caller of ALooper_pollOnce()
      * or ALooper_pollAll() MUST check the return from these functions to
@@ -69,66 +56,42 @@
 };
 
 /**
- * Prepare an ALooper associated with the calling thread, and return it.
- * If the thread already has an ALooper, it is returned.  Otherwise, a new
+ * Prepares a looper associated with the calling thread, and returns it.
+ * If the thread already has a looper, it is returned.  Otherwise, a new
  * one is created, associated with the thread, and returned.
  *
  * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
  */
-ALooper* ALooper_prepare(int32_t opts);
+ALooper* ALooper_prepare(int opts);
 
 enum {
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
-     * more callbacks were executed.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * The poll was awoken using wake() before the timeout expired
+     * and no callbacks were executed and no other file descriptors were ready.
      */
-    ALOOPER_POLL_CALLBACK = -1,
-    
+    ALOOPER_POLL_WAKE = -1,
+
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): the
-     * timeout expired.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * One or more callbacks were executed.
      */
-    ALOOPER_POLL_TIMEOUT = -2,
-    
+    ALOOPER_POLL_CALLBACK = -2,
+
     /**
-     * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
-     * occurred.
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * The timeout expired.
      */
-    ALOOPER_POLL_ERROR = -3,
+    ALOOPER_POLL_TIMEOUT = -3,
+
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll():
+     * An error occurred.
+     */
+    ALOOPER_POLL_ERROR = -4,
 };
 
 /**
- * Wait for events to be available, with optional timeout in milliseconds.
- * Invokes callbacks for all file descriptors on which an event occurred.
- *
- * If the timeout is zero, returns immediately without blocking.
- * If the timeout is negative, waits indefinitely until an event appears.
- *
- * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
- *
- * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
- * timeout expired.
- *
- * Returns ALOPER_POLL_ERROR if an error occurred.
- *
- * Returns a value >= 0 containing an identifier if its file descriptor has data
- * and it has no callback function (requiring the caller here to handle it).
- * In this (and only this) case outEvents and outData will contain the poll
- * events and data associated with the fd.
- *
- * This method does not return until it has finished invoking the appropriate callbacks
- * for all file descriptors that were signalled.
- */
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
-
-/**
- * Like ALooper_pollOnce(), but performs all pending callbacks until all
- * data has been consumed or a file descriptor is available with no callback.
- * This function will never return ALOOPER_POLL_CALLBACK.
- */
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
-
-/**
  * Acquire a reference on the given ALooper object.  This prevents the object
  * from being deleted until the reference is removed.  This is only needed
  * to safely hand an ALooper from one thread to another.
@@ -141,36 +104,140 @@
 void ALooper_release(ALooper* looper);
 
 /**
- * Add a new file descriptor to be polled by the looper.  If the same file
- * descriptor was previously added, it is replaced.
+ * Flags for file descriptor events that a looper can monitor.
+ *
+ * These flag bits can be combined to monitor multiple events at once.
+ */
+enum {
+    /**
+     * The file descriptor is available for read operations.
+     */
+    ALOOPER_EVENT_INPUT = 1 << 0,
+
+    /**
+     * The file descriptor is available for write operations.
+     */
+    ALOOPER_EVENT_OUTPUT = 1 << 1,
+
+    /**
+     * The file descriptor has encountered an error condition.
+     *
+     * The looper always sends notifications about errors; it is not necessary
+     * to specify this event flag in the requested event set.
+     */
+    ALOOPER_EVENT_ERROR = 1 << 2,
+
+    /**
+     * The file descriptor was hung up.
+     * For example, indicates that the remote end of a pipe or socket was closed.
+     *
+     * The looper always sends notifications about hangups; it is not necessary
+     * to specify this event flag in the requested event set.
+     */
+    ALOOPER_EVENT_HANGUP = 1 << 3,
+};
+
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called.  It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT),
+ * and the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
+typedef int (*ALooper_callbackFunc)(int fd, int events, void* data);
+
+/**
+ * Waits for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+ * the timeout expired and no callbacks were invoked and no other file
+ * descriptors were ready.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outFd, outEvents and outData will contain the poll
+ * events and data associated with the fd, otherwise they will be set to NULL.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+
+/**
+ * Wakes the poll asynchronously.
+ *
+ * This method can be called on any thread.
+ * This method returns immediately.
+ */
+void ALooper_wake(ALooper* looper);
+
+/**
+ * Adds a new file descriptor to be polled by the looper.
+ * If the same file descriptor was previously added, it is replaced.
  *
  * "fd" is the file descriptor to be added.
- * "ident" is an identifier for this event, which is returned from
- * ALooper_pollOnce().  Must be >= 0, or ALOOPER_POLL_CALLBACK if
- * providing a non-NULL callback.
- * "events" are the poll events to wake up on.  Typically this is POLLIN.
- * "callback" is the function to call when there is an event on the file
- * descriptor.
+ * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+ * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+ * "events" are the poll events to wake up on.  Typically this is ALOOPER_EVENT_INPUT.
+ * "callback" is the function to call when there is an event on the file descriptor.
  * "data" is a private data pointer to supply to the callback.
  *
  * There are two main uses of this function:
  *
- * (1) If "callback" is non-NULL, then
- * this function will be called when there is data on the file descriptor.  It
- * should execute any events it has pending, appropriately reading from the
- * file descriptor.  The 'ident' is ignored in this case.
+ * (1) If "callback" is non-NULL, then this function will be called when there is
+ * data on the file descriptor.  It should execute any events it has pending,
+ * appropriately reading from the file descriptor.  The 'ident' is ignored in this case.
  *
  * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
  * when its file descriptor has data available, requiring the caller to take
  * care of processing it.
+ *
+ * Returns 1 if the file descriptor was added or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
  */
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
-        ALooper_callbackFunc* callback, void* data);
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+        ALooper_callbackFunc callback, void* data);
 
 /**
- * Remove a previously added file descriptor from the looper.
+ * Removes a previously added file descriptor from the looper.
+ *
+ * When this method returns, it is safe to close the file descriptor since the looper
+ * will no longer have a reference to it.  However, it is possible for the callback to
+ * already be running or for it to run one last time if the file descriptor was already
+ * signalled.  Calling code is responsible for ensuring that this case is safely handled.
+ * For example, if the callback takes care of removing itself during its own execution either
+ * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+ * again at any later time unless registered anew.
+ *
+ * Returns 1 if the file descriptor was removed, 0 if none was previously registered
+ * or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
  */
-int32_t ALooper_removeFd(ALooper* looper, int fd);
+int ALooper_removeFd(ALooper* looper, int fd);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index a102d43..f163f18 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -166,7 +166,7 @@
  * Creates a new sensor event queue and associate it with a looper.
  */
 ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
-        ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+        ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
 
 /*
  * Destroys the event queue and free all resources associated to it.
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6e8b42e..cfba07a 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -826,6 +826,15 @@
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
+
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         // Redundant probably. But no harm in updating state again.
         mPms.updateExternalMediaStatus(false, false);
         try {
@@ -1277,6 +1286,14 @@
         waitForReady();
         warnOnNotMounted();
 
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
@@ -1341,6 +1358,14 @@
             }
          }
 
+        /*
+         * Force a GC to make sure AssetManagers in other threads of the
+         * system_server are cleaned up. We have to do this since AssetManager
+         * instances are kept as a WeakReference and it's possible we have files
+         * open on the external storage.
+         */
+        Runtime.getRuntime().gc();
+
         int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
         try {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index af8d7d4..8ab1bb8 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -660,28 +660,38 @@
     }
 
     void noteStartWakeLocked(WakeLock wl, WorkSource ws) {
-        try {
-            if (ws != null) {
-                mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
-                        wl.monitorType);
-            } else {
-                mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+        if (wl.monitorType >= 0) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                if (ws != null) {
+                    mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
+                            wl.monitorType);
+                } else {
+                    mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+                }
+            } catch (RemoteException e) {
+                // Ignore
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-        } catch (RemoteException e) {
-            // Ignore
         }
     }
 
     void noteStopWakeLocked(WakeLock wl, WorkSource ws) {
-        try {
-            if (ws != null) {
-                mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
-                        wl.monitorType);
-            } else {
-                mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+        if (wl.monitorType >= 0) {
+            long origId = Binder.clearCallingIdentity();
+            try {
+                if (ws != null) {
+                    mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
+                            wl.monitorType);
+                } else {
+                    mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+                }
+            } catch (RemoteException e) {
+                // Ignore
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-        } catch (RemoteException e) {
-            // Ignore
         }
     }
 
@@ -813,21 +823,16 @@
         if (ws != null) {
             enforceWakeSourcePermission(uid, pid);
         }
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLocks) {
-                int index = mLocks.getIndex(lock);
-                if (index < 0) {
-                    throw new IllegalArgumentException("Wake lock not active");
-                }
-                WakeLock wl = mLocks.get(index);
-                WorkSource oldsource = wl.ws;
-                wl.ws = ws != null ? new WorkSource(ws) : null;
-                noteStopWakeLocked(wl, oldsource);
-                noteStartWakeLocked(wl, ws);
+        synchronized (mLocks) {
+            int index = mLocks.getIndex(lock);
+            if (index < 0) {
+                throw new IllegalArgumentException("Wake lock not active");
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+            WakeLock wl = mLocks.get(index);
+            WorkSource oldsource = wl.ws;
+            wl.ws = ws != null ? new WorkSource(ws) : null;
+            noteStopWakeLocked(wl, oldsource);
+            noteStartWakeLocked(wl, ws);
         }
     }
 
@@ -884,14 +889,7 @@
         // Unlink the lock from the binder.
         wl.binder.unlinkToDeath(wl, 0);
 
-        if (wl.monitorType >= 0) {
-            long origId = Binder.clearCallingIdentity();
-            try {
-                noteStopWakeLocked(wl, wl.ws);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
+        noteStopWakeLocked(wl, wl.ws);
     }
 
     private class PokeLock implements IBinder.DeathRecipient
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4a9c9e9..859de46 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -518,14 +518,8 @@
         });
 
         // For debug builds, log event loop stalls to dropbox for analysis.
-        // Similar logic also appears in ActivityThread.java for system apps.
-        if (!"user".equals(Build.TYPE)) {
-            Slog.i(TAG, "Enabling StrictMode for system server.");
-            StrictMode.setThreadPolicy(
-                StrictMode.DISALLOW_DISK_WRITE |
-                StrictMode.DISALLOW_DISK_READ |
-                StrictMode.DISALLOW_NETWORK |
-                StrictMode.PENALTY_DROPBOX);
+        if (StrictMode.conditionallyEnableDebugLogging()) {
+            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
         }
 
         Looper.loop();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 124da4e..c837a3a 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -727,9 +727,10 @@
         }
     }
 
+    // Called by SystemBackupAgent after files are restored to disk.
     void settingsRestored() {
         if (DEBUG) Slog.v(TAG, "settingsRestored");
-        
+
         boolean success = false;
         synchronized (mLock) {
             loadSettingsLocked();
@@ -766,7 +767,10 @@
             mName = "";
             WALLPAPER_FILE.delete();
         }
-        saveSettingsLocked();
+
+        synchronized (mLock) {
+            saveSettingsLocked();
+        }
     }
 
     boolean restoreNamedResourceLocked() {
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index c95546e..0cb6943 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -45,8 +45,8 @@
         uri = _uri;
     }
     
-    void clearModes(int modeFlags) {
-        if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+    void clearModes(int modeFlagsToClear) {
+        if ((modeFlagsToClear&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             if (readOwners.size() > 0) {
@@ -56,7 +56,7 @@
                 readOwners.clear();
             }
         }
-        if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+        if ((modeFlagsToClear&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             if (readOwners.size() > 0) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3025f77..e204e04 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -529,7 +529,7 @@
     LOGE_IF(size<0, "dropping %d events on the floor (%s)",
             count, strerror(-size));
 
-    return size < 0 ? size : NO_ERROR;
+    return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
 sp<SensorChannel> SensorService::SensorEventConnection::getSensorChannel() const
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index e464713..42bf983 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -18,11 +18,11 @@
 #include <gui/Sensor.h>
 #include <gui/SensorManager.h>
 #include <gui/SensorEventQueue.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
 
 using namespace android;
 
-bool receiver(int fd, int events, void* data)
+int receiver(int fd, int events, void* data)
 {
     sp<SensorEventQueue> q((SensorEventQueue*)data);
     ssize_t n;
@@ -41,7 +41,7 @@
     if (n<0 && n != -EAGAIN) {
         printf("error reading events (%s)\n", strerror(-n));
     }
-    return true;
+    return 1;
 }
 
 
@@ -51,7 +51,7 @@
 
     Sensor const* const* list;
     ssize_t count = mgr.getSensorList(&list);
-    printf("numSensors=%d\n", count);
+    printf("numSensors=%d\n", int(count));
 
     sp<SensorEventQueue> q = mgr.createEventQueue();
     printf("queue=%p\n", q.get());
@@ -63,13 +63,16 @@
 
     q->setEventRate(accelerometer, ms2ns(10));
 
-    sp<PollLoop> loop = new PollLoop(false);
-    loop->setCallback(q->getFd(), POLLIN, receiver, q.get());
+    sp<Looper> loop = new Looper(false);
+    loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
 
     do {
         //printf("about to poll...\n");
-        int32_t ret = loop->pollOnce(-1, 0, 0);
+        int32_t ret = loop->pollOnce(-1);
         switch (ret) {
+            case ALOOPER_POLL_WAKE:
+                //("ALOOPER_POLL_WAKE\n");
+                break;
             case ALOOPER_POLL_CALLBACK:
                 //("ALOOPER_POLL_CALLBACK\n");
                 break;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..0515110 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -296,6 +296,10 @@
     return mNativeWindow->compositionComplete();
 }
 
+int DisplayHardware::getCurrentBufferIndex() const {
+    return mNativeWindow->getCurrentBufferIndex();
+}
+
 void DisplayHardware::flip(const Region& dirty) const
 {
     checkGLErrors();
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..2d7900c 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -87,6 +87,9 @@
         return Rect(mWidth, mHeight);
     }
 
+    // only for debugging
+    int getCurrentBufferIndex() const;
+
 private:
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 637ae48..f199ca9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,6 +38,7 @@
 #include <utils/StopWatch.h>
 
 #include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicLog.h>
 #include <ui/PixelFormat.h>
 
 #include <pixelflinger/pixelflinger.h>
@@ -371,15 +372,25 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (LIKELY(hw.canDraw() && !isFrozen())) {
         // repaint the framebuffer (if needed)
+
+        const int index = hw.getCurrentBufferIndex();
+        GraphicLog& logger(GraphicLog::getInstance());
+
+        logger.log(GraphicLog::SF_REPAINT, index);
         handleRepaint();
 
         // inform the h/w that we're done compositing
+        logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
         hw.compositionComplete();
 
         // release the clients before we flip ('cause flip might block)
+        logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
         unlockClients();
 
+        logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
         postFramebuffer();
+
+        logger.log(GraphicLog::SF_REPAINT_DONE, index);
     } else {
         // pretend we did the post
         unlockClients();
@@ -1470,8 +1481,7 @@
         int n;
         switch (code) {
             case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
-                return NO_ERROR;
-            case 1001:  // SHOW_FPS, NOT SUPPORTED ANYMORE
+            case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
                 return NO_ERROR;
             case 1002:  // SHOW_UPDATES
                 n = data.readInt32();
@@ -1492,6 +1502,11 @@
                 setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
                 return NO_ERROR;
             }
+            case 1006:{ // enable/disable GraphicLog
+                int enabled = data.readInt32();
+                GraphicLog::getInstance().setEnabled(enabled);
+                return NO_ERROR;
+            }
             case 1007: // set mFreezeCount
                 mFreezeCount = data.readInt32();
                 mFreezeDisplayTime = 0;
diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java
index c4204fa..313bc82 100644
--- a/telephony/java/android/telephony/gsm/GsmCellLocation.java
+++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java
@@ -60,8 +60,10 @@
     }
 
     /**
+     * On a UMTS network, returns the primary scrambling code of the serving
+     * cell.
+     *
      * @return primary scrambling code for UMTS, -1 if unknown or GSM
-     * @hide
      */
     public int getPsc() {
         return mPsc;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 4bf3282..8bd789c 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
+import android.os.Registrant;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.util.Log;
@@ -75,6 +76,7 @@
     private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
     private static final int EVENT_SUPP_SERVICE_FAILED = 117;
     private static final int EVENT_SERVICE_STATE_CHANGED = 118;
+    private static final int EVENT_POST_DIAL_CHARACTER = 119;
 
     // Singleton instance
     private static final CallManager INSTANCE = new CallManager();
@@ -158,6 +160,9 @@
     protected final RegistrantList mServiceStateChangedRegistrants
     = new RegistrantList();
 
+    protected final RegistrantList mPostDialCharacterRegistrants
+    = new RegistrantList();
+
     private CallManager() {
         mPhones = new ArrayList<Phone>();
         mRingingCalls = new ArrayList<Call>();
@@ -334,6 +339,7 @@
     }
 
     private void registerForPhoneStates(Phone phone) {
+        // for common events supported by all phones
         phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
         phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
         phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
@@ -342,20 +348,31 @@
         phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
         phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
         phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
-        phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
         phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
         phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
-        phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
         phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
         phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
         phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
-        phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
-        phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
         phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
         phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
+
+        // for events supported only by GSM and CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+                phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+            phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
+        }
+
+        // for events supported only by CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+            phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
+            phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
+            phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
+            phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
+        }
     }
 
     private void unregisterForPhoneStates(Phone phone) {
+        //  for common events supported by all phones
         phone.unregisterForPreciseCallStateChanged(mHandler);
         phone.unregisterForDisconnect(mHandler);
         phone.unregisterForNewRingingConnection(mHandler);
@@ -364,17 +381,27 @@
         phone.unregisterForRingbackTone(mHandler);
         phone.unregisterForInCallVoicePrivacyOn(mHandler);
         phone.unregisterForInCallVoicePrivacyOff(mHandler);
-        phone.unregisterForCallWaiting(mHandler);
         phone.unregisterForDisplayInfo(mHandler);
         phone.unregisterForSignalInfo(mHandler);
-        phone.unregisterForCdmaOtaStatusChange(mHandler);
         phone.unregisterForResendIncallMute(mHandler);
         phone.unregisterForMmiInitiate(mHandler);
         phone.unregisterForMmiComplete(mHandler);
-        phone.unregisterForEcmTimerReset(mHandler);
-        phone.unregisterForSubscriptionInfoReady(mHandler);
         phone.unregisterForSuppServiceFailed(mHandler);
         phone.unregisterForServiceStateChanged(mHandler);
+
+        // for events supported only by GSM and CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+                phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+            phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
+        }
+
+        // for events supported only by CDMA phone
+        if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+            phone.unregisterForCdmaOtaStatusChange(mHandler);
+            phone.unregisterForSubscriptionInfoReady(mHandler);
+            phone.unregisterForCallWaiting(mHandler);
+            phone.unregisterForEcmTimerReset(mHandler);
+        }
     }
 
     /**
@@ -1132,6 +1159,46 @@
         mSubscriptionInfoReadyRegistrants.remove(h);
     }
 
+    /**
+     * Sets an event to be fired when the telephony system processes
+     * a post-dial character on an outgoing call.<p>
+     *
+     * Messages of type <code>what</code> will be sent to <code>h</code>.
+     * The <code>obj</code> field of these Message's will be instances of
+     * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
+     * a Connection object.<p>
+     *
+     * Message.arg1 will be the post dial character being processed,
+     * or 0 ('\0') if end of string.<p>
+     *
+     * If Connection.getPostDialState() == WAIT,
+     * the application must call
+     * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
+     * Connection.proceedAfterWaitChar()} or
+     * {@link com.android.internal.telephony.Connection#cancelPostDial()
+     * Connection.cancelPostDial()}
+     * for the telephony system to continue playing the post-dial
+     * DTMF sequence.<p>
+     *
+     * If Connection.getPostDialState() == WILD,
+     * the application must call
+     * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
+     * Connection.proceedAfterWildChar()}
+     * or
+     * {@link com.android.internal.telephony.Connection#cancelPostDial()
+     * Connection.cancelPostDial()}
+     * for the telephony system to continue playing the
+     * post-dial DTMF sequence.<p>
+     *
+     */
+    public void registerForPostDialCharacter(Handler h, int what, Object obj){
+        mPostDialCharacterRegistrants.addUnique(h, what, obj);
+    }
+
+    public void unregisterForPostDialCharacter(Handler h){
+        mPostDialCharacterRegistrants.remove(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
@@ -1144,22 +1211,22 @@
     /**
      * @return list of all ringing calls
      */
-    public ArrayList<Call> getRingingCalls() {
-        return mRingingCalls;
+    public List<Call> getRingingCalls() {
+        return Collections.unmodifiableList(mRingingCalls);
     }
 
     /**
      * @return list of all foreground calls
      */
-    public ArrayList<Call> getForegroundCalls() {
-        return mForegroundCalls;
+    public List<Call> getForegroundCalls() {
+        return Collections.unmodifiableList(mForegroundCalls);
     }
 
     /**
      * @return list of all background calls
      */
-    public ArrayList<Call> getBackgroundCalls() {
-        return mBackgroundCalls;
+    public List<Call> getBackgroundCalls() {
+        return Collections.unmodifiableList(mBackgroundCalls);
     }
 
     /**
@@ -1269,7 +1336,7 @@
 
     /**
      * @return the connections of active foreground call
-     * return null if there is no active foreground call
+     * return empty list if there is no active foreground call
      */
     public List<Connection> getFgCallConnections() {
         Call fgCall = getActiveFgCall();
@@ -1408,6 +1475,18 @@
                     break;
                 case EVENT_SERVICE_STATE_CHANGED:
                     mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    break;
+                case EVENT_POST_DIAL_CHARACTER:
+                    // we need send the character that is being processed in msg.arg1
+                    // so can't use notifyRegistrants()
+                    for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
+                        Message notifyMsg;
+                        notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
+                        notifyMsg.obj = msg.obj;
+                        notifyMsg.arg1 = msg.arg1;
+                        notifyMsg.sendToTarget();
+                    }
+                    break;
             }
         }
     };
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
index fd87e89..5b5be0a 100644
--- a/tests/CoreTests/android/core/SSLPerformanceTest.java
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -211,17 +211,17 @@
         deleteDirectory();
 
         OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
-        sslContext.engineInit(null, null, null,
-                FileClientSessionCache.usingDirectory(getCacheDirectory()),
-                null);
+        sslContext.engineInit(null, null, null);
+        sslContext.engineGetClientSessionContext().setPersistentCache(
+                FileClientSessionCache.usingDirectory(getCacheDirectory()));
 
         // Make sure www.google.com is in the cache.
         getVerisignDotCom(sslContext);
 
         // Re-initialize so we hit the file cache.
-        sslContext.engineInit(null, null, null,
-                FileClientSessionCache.usingDirectory(getCacheDirectory()),
-                null);
+        sslContext.engineInit(null, null, null);
+        sslContext.engineGetClientSessionContext().setPersistentCache(
+                FileClientSessionCache.usingDirectory(getCacheDirectory()));
 
         Stopwatch stopwatch = new Stopwatch();
 
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
index 021df80..03905e1 100644
--- a/tests/CoreTests/android/core/SSLSocketTest.java
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -911,7 +911,8 @@
 
         // Cache size = 2.
         FakeClientSessionCache fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         SSLSocketFactory socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(2);
         makeRequests(socketFactory);
@@ -933,7 +934,8 @@
 
         // Cache size = 3.
         fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(3);
         makeRequests(socketFactory);
@@ -952,7 +954,8 @@
 
         // Cache size = 4.
         fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null, fakeCache, null);
+        context.engineInit(null, null, null);
+        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
         socketFactory = context.engineGetSocketFactory();
         context.engineGetClientSessionContext().setSessionCacheSize(4);
         makeRequests(socketFactory);
@@ -1010,7 +1013,8 @@
         try {
             ClientSessionCacheProxy cacheProxy
                     = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null, cacheProxy, null);
+            context.engineInit(null, null, null);
+            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
             SSLSocketFactory socketFactory = context.engineGetSocketFactory();
             context.engineGetClientSessionContext().setSessionCacheSize(1);
             makeRequests(socketFactory);
@@ -1033,7 +1037,8 @@
             // Try again now that file-based cache is populated.
             fileCache = FileClientSessionCache.usingDirectory(cacheDir);
             cacheProxy = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null, cacheProxy, null);
+            context.engineInit(null, null, null);
+            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
             socketFactory = context.engineGetSocketFactory();
             context.engineGetClientSessionContext().setSessionCacheSize(1);
             makeRequests(socketFactory);